HanLP关键词提取算法的示例分析
这篇文章主要为大家展示了“HanLP关键词提取算法的示例分析”,内容简而易懂,条理清晰,希望能够帮助大家解决疑惑,下面让小编带领大家一起研究并学习一下“HanLP关键词提取算法的示例分析”这篇文章吧。
HanLP 关键词提取算法分析1. 论文Inthispaper,weintroducetheTextRankgraphbasedrankingmodelforgraphsextractedfromnaturallanguagetexts
TextRank是一个非监督学习算法,它将文本中构造成一个图,将文本中感兴趣的东西(比如分词)当成一个个顶点,然后应用TextRank算法来抽取文本中的一些信息。
Suchkeywordsmayconstituteusefulentriesforbuildinganautomaticindexforadocumentcollection,canbeusedtoclassifyatext,ormayserveasaconcisesummaryforagivendocument.
提取出来的关键词,可用来作为文本分类,或者概括文本的中心思想。
TextRank通过不断地迭代来提取关键词,每一轮迭代,算法给图中的顶点打分。直到满足某个条件(比如说迭代次数克到200次,或者设置的某个参数达到一个阈值)为止。
Forlooselyconnectedgraphs,withthenumberofedgesproportionalwiththenumberofvertices,undirectedgraphstendtohavemoregradualconvergencecurves.
对于稀疏图而言,边的数目与顶点的数目成线性关系,对这样的图进行关键词提取,有着更平缓的收敛曲线(或者叫收敛得慢吧)
Itmaybethereforeusefultoindicateandincorporateintothemodelthe“strength”oftheconnectionbetweentwovertices$V_i$and$V_j$asaweight$w_{ij}$addedtothecorrespondingedgethatconnectsthetwovertices.
有时,图中顶点之间的关系并不完全平等,比如某些顶点之间关系密切,这里可用边的权重来衡量顶点之间的相关性重要程度,而这就是带权图模型。
2. 源码实现2.1 关键词提取流程给定若干个句子,提取关键词。而TextRank算法是 graphbased ranking model,因此需要构造一个图,要想构造图,就需要确定图中的顶点如何构造,于是就把句子进行分词,将分得的每个词作为图中的顶点。
在选取某个词作为图的顶点的时候,可以应用一些过滤规则:比如说,去除掉分词结果中的停用词、根据词性来添加顶点(比如只将名词和动词作为图的顶点)……
Theverticesaddedtothegraphcanberestrictedwithsyntacticfilters,whichselectonlylexicalunitsofacertainpartofspeech.Onecanforinstanceconsideronlynounsandverbsforadditiontothegraph,andconsequentlydrawpotentialedgesbasedonlyonrelationsthatcanbeestablishedbetweennounsandverbs.
在确定好哪些词作为图的顶点之后,另一个是确定词与词之间的关系,也即:图中的哪些顶点有边?比如说设置一个窗口大小,落在这个窗口内的词,都添加一条边。
itistheapplicationthatdictatesthetypeofrelationsthatareusedtodrawconnectionsbetweenanytwosuchvertices,
确定了边的关系后,接下来是确定边上权值。这个也是根据实际情况而定。
2.2 根据窗口大小确定词的邻接点前面提到,若干句话分词之后,得到的一个个的词,或者叫Term。假设窗口大小为5。解释一下TextRank算法提取关键词的Java实现文章中提到的如何确定某个Term有哪些邻接Term。
比如说:‘程序员‘ 这个Term,它在多个句子中出现了,因此分词结果‘程序员‘ 出现在四个地方:
索引0处:‘程序员‘的邻接点有:
英文、programmer、从事、程序
索引9处:‘程序员‘的邻接点有:
开发、维护、专业、人员、分为、程序、设计、人员
索引26处,‘程序员‘的邻接点有:
中国、软件、从业人员、分为、高级、程序员、系统分析员、项目经理
索引28处,‘程序员‘的邻接点有:
从业人员、分为、程序员、高级、系统分析员、项目经理、四大
结合这四处窗口中的所有的词,得到‘程序员‘的邻接点如下:
因此,当窗口大小设置为5时,Term的前后四个Term都将视为它的邻接点,并且当这个Term出现多次时,则是将它各次出现位置处的前后4个Term合并,最终作为这个Term的邻接点。
从这里可看出:如果某个Term在句子中出现了多次,意味着该Term会比较重要。因为它的邻接点会比较多,也即有很多其他Term给它投了票。这就有点类似于Term Frequency来衡量Term的重要性。
2.3 得分(score)的更新算法m.put(key, m.get(key) + d / size * (score.get(element) == null ? 0 : score.get(element)));
代码的解读:
m.get(key)
如果是第一次进入for (String element : value)
,则是拿到公式前半部分1-d
的结果;如果是已经在for (String element : value)
进行了迭代,for循环相当于求和:\(\Sigma_{v_j\in In(v_i)}\)
for(Stringelement:value){intsize=words.get(element).size();m.put(key,m.get(key)+d/size*(score.get(element)==null?0:score.get(element)));}
以”他说的确实在理“ 举例来说:,选取窗口大小为5,经过分词并去除停用词后:
构造的无向图如下:(每条边的权值都为1)
以顶点‘理‘为例,来看一下‘理‘的得分是如何被更新的。在for (String element : value)
一共有两个顶点对 ‘理‘进行投票,首先是 ‘确实‘顶点,与‘确实‘顶点邻接的顶点有两个,因此:int size = words.get(element).size();
中size=2。接下来,来分解一下这行代码:
m.put(key,m.get(key)+d/size*(score.get(element)==null?0:score.get(element)))
m.get(key)
为1-d,因为在外层for循环中,m.put(key, 1 - d)
已经公式的前半分部(1-d)存储了。
score.get(element) == null ? 0 : score.get(element)
这个是获取上一轮迭代的结果。对于初始第一轮迭代而言,score.get(element)
为0.8807971,这个值是每个顶点的得分初始值:
//依据TF来设置初值,words代表的是一张无向图for(Map.Entry<String,Set<String>>entry:words.entrySet()){score.put(entry.getKey(),sigMoid(entry.getValue().size()));//无向图的每个顶点得分值初始化}
score.get(element)
相当于公式中的\(WS(V_j)\)
最后来分析一个 size,size是由代码int size = words.get(element).size()
获得的,由于每条边权值为1,size其实相当于:\(\Sigma_{V_k\in Out(V_j)}w_{jk}\)。
In(‘理‘)={‘确实‘,‘说‘}
当\(V_j\)为‘确实‘时,\(Out(V_j)\)为{‘说‘,‘理‘},因此:\(\Sigma_{V_k\in Out(V_j)}w_{jk}=2\)。于是,更新顶点‘理‘的得分:\(1-d+d*(1/2)*0.8807971=0.5243387\)。然后再通过m.put将临时结果保存起来。
接下来,for (String element : value)
继续,此时:\(V_j\)为顶点‘说‘,由于顶点‘说‘也有两条邻接边,因此有:\(\Sigma_{V_k\in Out(V_j)}w_{jk}=2\)。于是更新顶点‘理‘的得分:\(0.5243387+d*(1/2)*0.8807971=0.89867747\)。而这就是第一轮迭代时,顶点‘理‘的得分。
根据上面的1、2中的步骤,for (String element : value)
就相当于:\(\Sigma_{V_j\in In(V_i)}\),因为每次都把计算好的结果再put回HashMap m中。
因此,在第一轮迭代中,顶点‘理‘的得分就是:0.89867747
类似于,经过:max_iter次迭代,或者达到阈值:
if(max_diff<=min_diff)break;
时,就不再迭代了。
下面再来对代码作个总体说明:
这里是构造无向图的过程
for(Stringw:wordList){if(!words.containsKey(w)){//排除了wordList中的重复term,对每个已去重的term,用TreeSet<String>保存该term的邻接顶点words.put(w,newTreeSet<String>());}//复杂度O(n-1)if(que.size()>=5){//窗口的大小为5,是写死的.对于一个term_A而言,它的前4个term、后4个term都属于term_A的邻接点que.poll();}for(StringqWord:que){if(w.equals(qWord)){continue;}//既然是邻居,那么关系是相互的,遍历一遍即可words.get(w).add(qWord);words.get(qWord).add(w);}que.offer(w);}
这里是对图中每个顶点赋值一个初始score过程:
Map<String,Float>score=newHashMap<String,Float>();//保存最终每个关键词的得分//依据TF来设置初值,words代表的是一张无向图for(Map.Entry<String,Set<String>>entry:words.entrySet()){score.put(entry.getKey(),sigMoid(entry.getValue().size()));//无向图的每个顶点得分值初始化}
接下来,三个for循环:第一个for循环代表迭代次数;第二个for循环代表:对无向图中每一个顶点计算得分;第三个for循环代表:对某个具体的顶点而言,计算它的每个邻接点给它的投票权重。
for(inti=0;i<max_iter;++i){//....for(Map.Entry<String,Set<String>>entry:words.entrySet()){//...for(Stringelement:value){
这样,就实现了论文中公式:
\[WS(v_i)=(1-d)+d*\Sigma_{V_j\in In(V_i)}\frac{w_{ji}}{\Sigma_{V_k\in Out(V_j)}w_{jk}}*WS(V_j)\]
而最终提取出来的关键词是:
[理, 确实, 说]
上面只是用 ”他说的确实在理“ 这句话 演示了TextRank算法的具体细节,在实际应用中可能不合理。因为会存在:
现有统计信息不足以让TextRank支持 某个词 的重要性,算法有局限性。
可见:TextRank提取关键词是受到分词结果的影响的;其次,也受窗口大小的影响。
以上是“HanLP关键词提取算法的示例分析”这篇文章的所有内容,感谢各位的阅读!相信大家都有了一定的了解,希望分享的内容对大家有所帮助,如果还想学习更多知识,欢迎关注亿速云行业资讯频道!
声明:本站所有文章资源内容,如无特殊说明或标注,均为采集网络资源。如若本站内容侵犯了原著者的合法权益,可联系本站删除。