赞
踩
原文作者:码农加油站
原文地址:http://www.jinciwei.cn/a135076.html
最近boss交代了一个任务,展示一个文档的关键词图,小农同学就努力学习起来,从结巴分词、Wordcloud到hanlp、echarts展示字符云。以下小农同学要总结一下学习到的关键词抽取的算法之一TF-IDF算法。
一个容易想到的思路,就是找到出现次数最多的词。如果某个词很重要,它应该在这篇文章中多次出现。于是,我们进行"词频"(Term Frequency,缩写为TF)统计。
结果你肯定猜到了,出现次数最多的词是----“的”、“是”、“在”----这一类最常用的词。它们叫做"停用词"(stop words),表示对找到结果毫无帮助、必须过滤掉的词。
假设我们把它们都过滤掉了,只考虑剩下的有实际意义的词。这样又会遇到了另一个问题,我们可能发现某些词的出现次数一样多。这是不是意味着,作为关键词,它们的重要性是一样的?
显然不是这样,我们需要一个重要性调整系数,衡量一个词是不是常见词。如果某个词比较少见,但是它在这篇文章中多次出现,那么它很可能就反映了这篇文章的特性,正是我们所需要的关键词。
用统计学语言表达,就是在词频的基础上,要对每个词分配一个"重要性"权重。最常见的词(“的”、“是”、“在”)给予最小的权重,较常见的词给予较小的权重,较少见的词给予较大的权重。这个权重叫做"逆文档频率"(Inverse Document Frequency,缩写为IDF),它的大小与一个词的常见程度成反比。
知道了"词频"(TF)和"逆文档频率"(IDF)以后,将这两个值相乘,就得到了一个词的TF-IDF值。某个词对文章的重要性越高,它的TF-IDF值就越大。所以,排在最前面的几个词,就是这篇文章的关键词。
下面就是这个算法的细节。
第一步,计算词频。
考虑到文章有长短之分,为了便于不同文章的比较,进行"词频"标准化。
或者
第二步,计算逆文档频率。
这时,需要一个语料库(corpus),用来模拟语言的使用环境。
如果一个词越常见,那么分母就越大,逆文档频率就越小越接近0。分母之所以要加1,是为了避免分母为0(即所有文档都不包含该词)。log表示对得到的值取对数。
第三步,计算TF-IDF。
可以看到,TF-IDF与一个词在文档中的出现次数成正比,与该词在整个语言中的出现次数成反比。所以,自动提取关键词的算法就很清楚了,就是计算出文档的每个词的TF-IDF值,然后按降序排列,取排在最前面的几个词。
结巴分词TF-IDF算法源码分析
基于TF-IDF算法抽取关键词的主调函数是TFIDF.extract_tags函数,主要是在jieba/analyse/tfidf.py中实现。
其中TFIDF是为TF-IDF算法抽取关键词所定义的类。类在初始化时,默认加载了分词函数tokenizer =jieba.dt、词性标注函数postokenizer = jieba.posseg.dt、停用词stop_words = self.STOP_WORDS.copy()、idf词典idf_loader = IDFLoader(idf_path or DEFAULT_IDF)等,并获取idf词典及idf中值(如果某个词没有出现在idf词典中,则将idf中值作为这个词的idf值)。
def__init__(self, idf_path=None):
self.tokenizer = jieba.dt
self.postokenizer = jieba.posseg.dt
self.stop_words = self.STOP_WORDS.copy()
self.idf_loader = IDFLoader(idf_path or DEFAULT_IDF)
self.idf_freq, self.median_idf = self.idf_loader.get_idf()
然后开始通过TF-IDF算法进行关键词抽取。
首先根据是否传入了词性限制集合,来决定是调用词性标注接口还是调用分词接口。例如,词性限制集合为[“ns”,“n”, “vn”, “v”, “nr”],表示只能从词性为地名、名词、动名词、动词、人名这些词性的词中抽取关键词。
1)如果传入了词性限制集合,首先调用词性标注接口,对输入句子进行词性标注,得到分词及对应的词性;依次遍历分词结果,如果该词的词性不在词性限制集合中,则跳过;如果词的长度小于2,或者词为停用词,则跳过;最后将满足条件的词添加到词频词典中,出现的次数加1;然后遍历词频词典,根据idf词典得到每个词的idf值,并除以词频词典中的次数总和,得到每个词的tf * idf值;如果设置了权重标志位,则根据tf-idf值对词频词典中的词进行降序排序,然后输出topK个词作为关键词;
2)如果没有传入词性限制集合,首先调用分词接口,对输入句子进行分词,得到分词;依次遍历分词结果,如果词的长度小于2,或者词为停用词,则跳过;最后将满足条件的词添加到词频词典中,出现的次数加1;然后遍历词频词典,根据idf词典得到每个词的idf值,并除以词频词典中的次数总和,得到每个词的tf * idf值;如果设置了权重标志位,则根据tf-idf值对词频词典中的词进行降序排序,然后输出topK个词作为关键词;
defextract_tags(self, sentence, topK=20,withWeight=False, allowPOS=(), withFlag=False):
if allowPOS:
allowPOS = frozenset(allowPOS)
words = self.postokenizer.cut(sentence)
else:
words = self.tokenizer.cut(sentence)
freq = {}
for w in words:
if allowPOS:
if w.flag notin allowPOS:
continue
elifnot withFlag:
w = w.word
wc = w.word if allowPOS and withFlag else w
if len(wc.strip()) < 2 or wc.lower() in self.stop_words:
continue
freq[w] = freq.get(w, 0.0) + 1.0
total = sum(freq.values())
for k in freq:
kw = k.word if allowPOS and withFlag else k
freq[k] *= self.idf_freq.get(kw,self.median_idf) / total
if withWeight:
tags = sorted(freq.items(),key=itemgetter(1), reverse=True)
else:
tags = sorted(freq,key=freq.getitem, reverse=True)
if topK:
return tags[:topK]
else:
return tags
其他相关:使用不同的方法计算TF-IDF值 https://www.jianshu.com/p/f3b92124cd2b
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。