(纯属为了记录自己学习的点滴过程,引用资料都附在参考列表)
1 基本概念
什么是关键词(是什么)
大略的讲就是文章中重要的单词,而不限于词语的新鲜程度。
什么样的单词是重要的单词,恐怕这是个见仁见智的问题,所以可以根据用户需求,合理设计先验知识融进模型进行建模,本文讨论的是最易于理解、最常见的几种度量“重要”的方式,也可以理解为几种常见理解“关键词”的观点。
2 问题
提取一篇文章的关键词;
3 解决思路
3.1 词频统计
先验知识:一方面,关键词通常在文章中反复出现,为了解释关键词,作者通常会反复提及它们;另一方面,反复出现的词语不一定是关键词,根据齐夫定律,一些词频高的往往是标点符号和助词’的‘等,它们显然不是关键词。
算法:根据先验知识,算法模型如下:
- 分词;
- 停用词过滤;
- 按词频提取前n个;
缺点:用词频来提取关键词有一个缺陷,那就是高频词并不等价于关键词。比如在一个体育网站中,所有文章都是奥运会报道,导致“奥运会”词频最高,用户希望通过关键词看到每篇文章的特色。此时,TF-IDF 就派上用场了。
3.2 IF-IDF
先验知识:如果某个词在一篇文档中出现的频率高,并且在其它文档中很少出现,则认为这个词有很好的类别区分能力。
TF-IDF的数学表达:
TF−IDF(t,d)=TF(t,d)DF(t)=TF(t,d)×IDF(t)TF-IDF(t,d) = \frac{TF(t, d)}{DF(t)} \\ =TF(t, d) \times IDF(t) TF−IDF(t,d)=DF(t)TF(t,d)=TF(t,d)×IDF(t)
其中,t 代表单词,d 代表文档,TF(t,d) 代表 t 在 d 中出现频次,DF(t) 代表有多少篇文档包含 t。DF 的倒数称为IDF,这也是 TF-IDF 得名的由来,这个数学式子正式上面基本思想的刻画。
改进:TF-IDF在大型语料库上的统计类似于一种学习过程,假如我们没有这么大型的语料库或者存储IDF的内存,同时又想改善词频统计的效果该怎么办呢?此时可以使用TextRank算法。
3.3 TextRank
基本思想:TextRank是大名鼎鼎的PageRank算法在文本上的应用。
Google用它来体现网页的相关性和重要性,在搜索引擎优化操作中是经常被用来评估网页优化的成效因素之一。
即对于某个网页A而言,该网页PageRank值的计算基于以下两个假设:
- 数量假设,如果越多的网页指向A,即A的入链数量越多,则该网页越重要;
- 质量假设,如果指向A的网页质量越高,则A越重要,即权重因素不同。
(PageRank的数学细节参考李航《统计学习方法》);
将 PageRank 应用到关键词提取,无非是将单词视作节点而已,另外,每个单词的外链来自自身前后固定大小的窗口内的所有单词。
4 实现
4.1 基于词频统计
- 这只是一个针对词频统计算法的演示性代码,也易于改成批处理的代码;
- 词频统计属于单文档算法,就是根据一篇文章(不借助其它文章)就可以分析该文章的关键词;
# -*- coding:utf-8 -*-from pyhanlp import *TermFrequency = JClass('com.hankcs.hanlp.corpus.occurrence.TermFrequency')
TermFrequencyCounter = JClass('com.hankcs.hanlp.mining.word.TermFrequencyCounter')if __name__ == '__main__':counter = TermFrequencyCounter()counter.add("加油加油中国队!") # 第一个文档counter.add("中国观众高呼加油中国") # 第二个文档for termFrequency in counter: # 遍历每个词与词频print("%s=%d" % (termFrequency.getTerm(), termFrequency.getFrequency()))print(counter.top(2)) # 取 top N# 根据词频提取关键词print(TermFrequencyCounter.getKeywordList("女排夺冠,观众欢呼女排女排女排!", 3))
运行结果:
中国=2
中国队=1
加油=3
观众=1
高呼=1
[加油=3, 中国=2]
[女排, 观众, 欢呼]
4.2 基于TF-IDF
- TF-IDF是基于多文档的统计量,所以要输入多篇文档后才能开始计算;
- 统计TF-IDF同样涉及分词和停用词过滤;
# -*- coding:utf-8 -*-from pyhanlp import *TfIdfCounter = JClass('com.hankcs.hanlp.mining.word.TfIdfCounter')if __name__ == '__main__':counter = TfIdfCounter()counter.add("《女排夺冠》", "女排北京奥运会夺冠") # 输入多篇文档counter.add("《羽毛球男单》", "北京奥运会的羽毛球男单决赛")counter.add("《女排》", "中国队女排夺北京奥运会金牌重返巅峰,观众欢呼女排女排女排!")counter.compute() # 输入完毕for id in counter.documents():print(id + " : " + counter.getKeywordsOf(id, 3).toString()) # 根据每篇文档的TF-IDF提取关键词# 根据语料库已有的IDF信息为语料库之外的新文档提取关键词print(counter.getKeywords("奥运会反兴奋剂", 2))
运行结果:
女排》 : [女排=5.150728289807123, 重返=1.6931471805599454, 巅峰=1.6931471805599454]
《女排夺冠》 : [夺冠=1.6931471805599454, 女排=1.2876820724517808, 奥运会=1.0]
《羽毛球男单》 : [决赛=1.6931471805599454, 羽毛球=1.6931471805599454, 男单=1.6931471805599454]
[反, 兴奋剂]
4.3 基于TextRank
- 词频统计属于单文档算法;
from pyhanlp import *""" 关键词提取"""
content = (
"程序员(英文Programmer)是从事程序开发、维护的专业人员。"
"一般将程序员分为程序设计人员和程序编码人员,"
"但两者的界限并不非常清楚,特别是在中国。"
"软件从业人员分为初级程序员、高级程序员、系统"
"分析员和项目经理四大类。")TextRankKeyword = JClass("com.hankcs.hanlp.summary.TextRankKeyword")
keyword_list = HanLP.extractKeyword(content, 5)
print(keyword_list)
运行结果:
[程序员, 程序, 分为, 人员, 软件]
5 参考文献
- https://www.jianshu.com/p/f6d66ab97332 《PageRank算法核心思想及数学支撑》;
- 何晗《自然语言处理入门》;
- 宗成庆《统计自然语言处理》;
- 李航《统计学习方法》;
6 需要解决的问题
- PageRank算法数学细节;