文本关键词提取TFIDF和TextRank.docx
- 文档编号:12867775
- 上传时间:2023-04-22
- 格式:DOCX
- 页数:39
- 大小:192.97KB
文本关键词提取TFIDF和TextRank.docx
《文本关键词提取TFIDF和TextRank.docx》由会员分享,可在线阅读,更多相关《文本关键词提取TFIDF和TextRank.docx(39页珍藏版)》请在冰豆网上搜索。
文本关键词提取TFIDF和TextRank
基于关键词提取的TFIDF和TextRank方法的对比研究
题目:
开发一个程序,在该程序中,允许输入一段文本(以界面或者文件输入方式均可),该程序自动抽取出包含的关键词,并按照关键词的权重由高到低排序后输出。
完成日期:
2016.06.05
一、需求分析
1.以文本的形式读入数据,将每个单词抽象成一棵树,将单词与单词之间的关系抽象为图。
2.TFIDF算法部分以EXCEL形式将所有数据输出,TextRank算法部分直接以窗口形式输出排名前十位的数据。
3.本程序的目的是在提取文本关键词的同时,比较TFDIF和TextRank算法的准确性和性能方面的差异。
4.测试数据(附后)。
二、概要设计
1.抽象数据类型映射树定义如下:
ADTMap{
数据对象ID:
ID是类型为char的元素集合,即为一个单词中的单个字
符,称为字符集。
数据对象val:
val是类型为double或int的元素集合,为每个单词对应
的TF值或IDF值,称为频率集。
数据对象is_end:
is_end是类型为bool的元素集合,判断当前子结点是
否为单词末尾
数据关系R:
R={IDVal}
IDVal={word–>num|word
ID,num
val,表示从word到num之间的一一映射}
运算符重载:
下标运算符[]:
运算对象为string值,返回对应string值的子树所代表的val值。
算术运算符=:
运算对象为double或int值,等式左值的val值替换为等式右值,并返回当前子树。
算术运算符+-*/:
运算对象为double或int值,对其val值进行运算,并返回当前子树。
相等运算符==和!
=:
运算对象为val值,判断其val值是否相等,返回对应的bool值。
基本操作:
InitMap(&T);
操作结果:
构造空树。
DestroyMap(&T);
初始条件:
树T存在。
操作结果:
构造空树。
CreateMap(&T,word);
初始条件:
树T存在且word为string值。
操作结果:
按照word的字符顺序自上而下遍历,如果有字符结点未创造,则构造新子结点,直到字符结束。
MapEmpty(T);
初始条件:
树T存在。
操作结果:
若T为空树,则返回True,否则False。
MapDepth(&T);
初始条件:
树T存在。
操作结果:
返回树的深度。
Root(&T);
初始条件:
树T存在。
操作结果:
返回T的根。
Value(&T,value);
初始条件:
树T存在,value为T中某个结点的值。
操作结果:
返回value的值。
Assign(&T,word,value);
初始条件:
树T存在,且word结点也存在。
操作结果:
结点word的value值替换为当前value。
Parent(&T,word);
初始条件:
树T存在,且word结点也存在。
操作结果:
返回word结点的双亲。
InsertWord(&T,word);
初始条件:
树T存在。
操作结果:
往树加入word值,并将其value值默认初始化。
DeleteChild(&T,word);
初始条件:
树T存在,且word结点也存在。
操作结果:
将word对应子节点的is_end值改为false。
TraverseMap(&T,visit());
初始条件:
树T存在,visit是对结点操作的应用函数。
操作结果:
按某种次序对T的每个结点调用visit一次且至多一次。
一旦visit失败,则操作失败。
}ADTMap
2.抽象数据类型图定义如下
ADT Graph{
数据对象n:
n是具有相同特征的数据元素集合,称为顶点集。
数据关系:
DR={
弧}
基本操作:
CreateGraph(&G, V,VR) ;
初始条件:
V是图的顶点集,VR是图中弧的集合
操作结果:
按V和VR的定义构造图G
DestroyGraph(&G);
初始条件:
图G存在
操作结果:
销毁图G
LocateVex(G, u);
初始条件:
图G已存在,u和G中顶点有相同特征
操作结果:
若G中存在顶点u,则返回该顶点在图中位置,
否则返回其它信息
GetVex(G, v);
初始条件:
图G存在,v是G中某个顶点
操作结果:
返回v的值
PutVex(&G, v, value);
初始条件:
图G存在,v是G中某个顶点
操作结果:
对v赋值value
FirstAdjVex(G, v);
初始条件:
图G存在,v是G中某个顶点
操作结果:
返回v的第一个邻接顶点。
若顶点在G中没有邻
接顶点,则返回“空”
NextAdjVex(G, v, w);
初始条件:
图G存在,v是G中某个顶点,w是v的邻接顶
点
操作结果:
返回v的(相对于w的)下一个邻接顶点。
若w是
v的最后一个邻接点,则返回"空”
InsertVex(&G, v);
初始条件:
图G存在,v和G中顶点有相同特征
操作结果:
在图中增添新顶点v
DeleteVex(&G, v);
初始条件:
图G存在,v是G中某个顶点
操作结果:
删除G中顶点v及其相关的弧
InsertArc(&G, v, w)
初始条件:
图G存在,v和w是G中两个顶点
操作结果:
在图G中增添弧
增添对称弧
DeleteArc(&G, v, w)
初始条件:
图G存在,v和w是G中两个顶点
操作结果:
删除G中的弧
除对称弧
DFSTraverse(G, v, visit())
初始条件:
图G存在,v是G中某个顶点,visit是对顶点
的应用函数
操作结果:
从顶点v起深度优先遍历图G,并对每个顶点调
用函数visit()一次且至多一次。
一旦visit()失败,则操作失败
BFSTraverse(G, v, visit())
初始条件:
图G存在,v是G中某个顶点,visit是对顶点
的应用函数
操作结果:
从顶点v起广度优先遍历图G,并对每个顶点调
用函数visit()一次且至多一次。
一旦
visit()失败,则操作失败
}ADT Graph
3.本程序包含两大模块,TF-IDF算法部分和TextRank算法部分
1)主函数部分
voidmain(){
TF-IDF算法;
TextRank算法;
}
2)TF-IDF算法
i.构建语料库(语料库的原料来源于超过八亿词的文本)
ii.导入语料库
iii.读入文本
iv.分析所读入的单词
v.合并语料库
vi.输出到EXCEL
3)TextRank算法
i.读入数据
ii.分析所读入的单词
iii.构造矩阵
iv.套用公式
v.结果排序
vi.输出前十名
各模块之间的调用关系如下:
三、详细设计
1.设计思路
本程序以实现关键词抽取为目的,选取了TF-IDF和TextRank关键词提取算法,进行两者的效率和准确性的比较研究。
2.TFIDF算法
2.1.TF-IDF算法简介
TF-IDF是一种统计方法,用以评估一字词对于一个文件集或一个语料库中的其中一个词组或短语的重要程度。
字词的重要性随着它在文件中出现的次数成正比增加,但同时会随着它在语料库中出现的频率成反比下降。
在一组文档中,刻画某一文档特征的特征项可以根据其在这组文档中出现的频率赋予相应的权重,只有在少数文档中出现的较特殊的词,权重要比在多篇文档中出现的词的权重要高。
TF-IDF加权的各种形式常被搜索引擎应用,作为文件与用户查询之间相关程度的度量或评级。
2.2.TF-IDF算法原理
TF-IDF实际上是TF和IDF的组合。
TF即词频(TermFrequency),IDF即逆向文档频率(InverseDocumentFrequency)。
TF(词频)就是某个词在文章中出现的次数,此文章为需要分析的文本。
为了统一标准,有如下两种计算方法【2】:
和
IDF(逆向文档频率)为该词的常见程度,需要构建一个语料库来模拟语言的使用环境。
如果一个词越常见,那么其分母就越大,IDF值就越小。
之后,将每个单词的TF-IDF值按从大到小降序排列,排在最前面的几个词即为关键词。
2.3.TF-IDF算法实现
2.3.1.构建一一映射Map类
C++STL函数库中已经包含了map的库函数,但为了使用起来更加方便、更便于个性化定制操作,于是使用自己定制的Map类模板。
这个类函数主要是构建单词的string值与其TF、IDF值的一一对应关系,方便直接用string值下标访问其int值或double值,简化写代码的工作量。
同时模板类中主要采取树形结构,建立一棵查找树,利用vector的空间动态分配的灵活性,从string的第一个字母开始一个一个往下找。
每个Map类代表一个字母,从根部开始向下遍历,利用bool值判断该处是否为一个单词结尾。
代码如下:
/*********************************************************************
*
*一一映射函数Map类
*Type为存储的TF、IDF、TF-IDF值,如int、double等
*旨在通过string类型下标访问其Type值
*
*********************************************************************/
template
classMap
{
public:
Typeval=NULL;//Type值,类型为int、double
/*********************************************************************
*
*下标运算符[]重载
*[]中值为string类型
*如果该string值已存在,则返回对应val
*如果不存在则新建一个,返回初始值
*
*********************************************************************/
Type&operator[](stringitem)
{
Map&temp=find(item);//引用类函数find()查找到的值
if(temp!
=NULL)//找到,则返回对应val
{
returntemp.val;
}
else//未找到,则用create()函数创建一个并返回新的值
{
create(item);
returnfind(item).val;
}
}
/*********************************************************************
*
*算术运算符=重载
*左值为找到的Map.val引用
*右值为对应的val值
*返回当前Map的引用
*
*********************************************************************/
Map&operator=(Typeitem)
{
val=item;
returnthis;
}
/*********************************************************************
*
*类函数列表
*find为查找函数,找到则返回其值,没找到则新建一个返回初值
*create为创建新值得函数
*
*********************************************************************/
Mapfind(stringword);
voidcreate(stringword);
private:
boolis_end=false;//是否为单词结尾
charID;//代表当前类的字母
vector
};
/*********************************************************************
*
*find查找函数
*如果该string值已存在,则返回对应值
*如果不存在则新建一个,返回初始值
*
*********************************************************************/
template
MapMap
:
find(stringword)
{
for(auto&r:
childs)//遍历类函数的所有子节点直到找到对应项
{
if(r->ID==word[0]&&r->is_end)//如果相等且为单词末尾
{
if(word.size()==1)//大小为一说明已找到
{
returnthis;//返回当前类
}
returnr->find(word.substr(1,word.size()-1));//递归调用find函数,一次减少一个字符
}
}
returnNULL;//返回空类
}
/*********************************************************************
*
*create创建函数
*递归创建字母树
*
*********************************************************************/
template
voidMap
:
create(stringword)
{
if(word.size()==0)//如果大小为0,说明所有字母都已创建完毕
{
is_end=true;//标记单词结尾为true
return;
}
for(auto&r:
childs)//遍历所有子节点
{
if(r->ID==word[0])//如果找到,则减少第一个字符,继续递归向下遍历
{
r->creat(word.substr(1,word.size()-1));
return;
}
}
Map*temp=newMap;//没找到,则新建一个Map
temp->ID=word[0];//将其所代表的字符ID设为当前word的第一个字符
childs.push_back(temp);//子节点中增加这一Map
temp->creat(word.substr(1,word.size()-1));//继续递归创建后续字符
return;
}
2.3.2.构建语料库
为了使语料库更符合本程序的应用场景,语料库采用自己构建的语料库。
语料库素材来源于小说新闻等,总词数超过8亿词。
因为每篇文档有几十万字,为了使词语的ITF更具普遍性,假设每1000词为一篇文章。
然后每次将文章先存入一个临时语料库中,进行分析处理后,将处理后的词加入临时语料库。
之后再将临时语料库合并入总的语料库,流程图如下:
//建立语料库
map
longlonginttimes=0;//文章总数,作为计算频率的基数
ofstreamoutput("corpus.csv");//输出到excel表格中存储
/*********************************************************************
*
*导入制作好的语料库
*存在一一映射corpus中
*
*********************************************************************/
voidbuildCorpus()
{
ifstreaminput("corpus.csv");//打开文件
stringitem;//定义临时存储变量string和double
doubleval;
while(!
input.eof())//读入文件,存储到语料库映射中
{
input>>item>>val;
corpus[item]=val;
}
}
/*********************************************************************
*
*分析处理读入的string短语
*先删去字符前的不必要符号如数字、标点"([{<等等
*将剩下的大写字符转化为小写
*保留字符中的标点,如Mr.Bill等
*再删除字符后的不必要标点,如.,"':
等等
*返回修改后的字符
*
*********************************************************************/
stringanalysis(stringitem)
{
stringtemp="";//定义空字符
boolflag=false;//flag标记,当碰到第一个字母时,flag变为true,否则为false,滤过不必要的前缀
for(auto&r:
item)//遍历string中每一个字符
{
if(r==','||r==';')//滤过,;等符号
{
continue;
}
if(r<='z'&&r>='a')//碰到字母标记true
{
flag=true;
}
if(r<='Z'&&r>='A')//转化大小写
{
flag=true;
r+=32;
}
if(flag)//如果已碰到字母,则在缓存string中加入该字符
{
temp+=r;
}
}
if(temp.size()==0)//如果是空字符,直接return
{
returntemp;
}
for(autoi=temp.rbegin();i<=temp.rend();i++)//从尾开始遍历string,删去string中不必要的后缀
{
if(*i<='z'&&*i>='a')//若碰到字母,则跳出循环
{
break;
}
temp.pop_back();//删去后缀
}
returntemp;//返回处理过的字符string
}
/*********************************************************************
*
*遍历临时语料库的数值
*将其合并到总的语料库
*
*********************************************************************/
voidprint(map
{
for(auto&r:
frequency)//遍历临时语料库
{
if(corpus.find(r.first)==corpus.end())//第一次出现则将在总语料库中新建一个,并将其初始化
{
corpus[r.first]=0.0;
}
corpus[r.first]++;//合并语料库中对应数值
}
}
/*********************************************************************
*
*创建语料库
*通过文件读入文章
*由于部分文章为小说,有几十万字,于是统一按每1000字为一篇文章
*语料库素材中所有文章的总次数大概有8亿词
*将该文章中出现的单词存入临时语料库中
*每一千字更新总语料库corpus,清空临时语料库frequency
*最后计算每个单词的IDF值
*
*********************************************************************/
voidreadDictEn()
{
intwords=0;//记录当前已读入的word词数,每一千字更新一次
map
longlongintcnt=0;//临时变量,记录临时语料库被清零多少次
for(inti=1;i<=633;i++)//遍历语料库素材TXT文档,共有633个TXT文档,每篇文档平均12万词
{
/*********************************************************************
*
*每篇文档的命名方式为"EN(i)",i为文档编号
*先利用stringstream流创建文件名的字符串
*再用ifstream流打开对应文件
*
*********************************************************************/
cout<
";//输出当前读入文件状态
ostringstreamout;//string
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 文本 关键词 提取 TFIDF TextRank