TF-IDF简介与应用

一、TF-IDF简介


  在自然语言处理中,TF-IDF(term frequency–inverse document frequency)常用于挖掘文章中的关键词, 算法以简单高效著称。TF-IDF有两层意思,一层是"词频"(Term Frequency,缩写为TF),另一层是"逆文档频率"(Inverse Document Frequency,缩写为IDF)。

  理论来讲, 一篇文章中词频的高低能反应该篇文章词语的关键性。可是在文章中词频高的往往是“的”、“了”之类的词语,这些在文档中最常见但对结果毫无帮助、需要过滤掉的词,用TF可以统计到这些停用词并把它们过滤。当高频词过滤后就只需考虑剩下的有实际意义的词。

  但这样又会遇到了另一个问题,我们可能发现某些常见的词语在文章中也挺多的,但是这些词语依旧不能可靠地作为该篇文章的关键词,因为它们在其他文章中也比较常见,所以这个时候就需要IDF,IDF会给常见的词较小的权重,它的大小与一个词的常见程度成反比。

  当有TF(词频)和IDF(逆文档频率)后,将这两个词相乘,就能得到一个词的TF-IDF的值。某个词在文章中的TF-IDF越大,那么一般而言这个词在这篇文章的重要性会越高,所以通过计算文章中各个词的TF-IDF,由大到小排序,排在最前面的几个词,就是该文章的关键词。

二、算法步骤


第一步,计算词频:

[词频(TF)= 某词在文章中出现的次数 ]

考虑到文章有长短之分,为了便于不同文章的比较,进行“词频”标准化。

[词频(TF)= frac{某词在文章中出现的次数}{文章的总词数} ]

第二步,计算逆文档频率:

这时,需要一个语料库(corpus),用来模拟语言的使用环境。

[逆文档频率(IDF)= log(frac{语料库的文档总数}{包含该词的文档数+1}) ]

如果一个词越常见,那么分母就越大,逆文档频率就越小越接近0。分母之所以要加1,是为了避免分母为0(即所有文档都不包含该词)。

第三步,计算TF-IDF:

[TF-IDF=词频(TF) imes 逆文档频率(IDF) ]

可以看到,TF-IDF与一个词在文档中的出现次数成正比,与该词在整个语言中的出现次数成反比。所以,自动提取关键词的算法就很清楚了,就是计算出文档的每个词的TF-IDF值,然后按降序排列,取排在最前面的几个词。

三、算法实现


import math
import jieba
from collections import Counter

STOP_WORDS = {' ', ',', ',', '!', '!', ':', ':', '的', '了', '是'}

corpus = [
    '作死!国王前锋感染新冠并未隔离 不戴口罩外出打球',
    '湖人媒体抱怨赛程安排太难:快船那么轻松不公平',
    '弥补财政损失的最快捷办法就是增加球队,得到的扩张费用会非常可观,而这笔钱他们无需跟球员分享'
]

word_list = []
for i in range(len(corpus)):
    word_list.append([token for token in jieba.lcut(corpus[i]) if token not in STOP_WORDS])
print(word_list)

count_list = []
for i in range(len(word_list)):
    count = Counter(word_list[i])
    count_list.append(count)
print(count_list)


# word可以通过count得到,count可以通过count_list得到
# count[word]可以得到每个单词的词频, sum(count.values())得到整个句子的单词总数
def tf(word, count):
    return count[word] / sum(count.values())


# 统计的是含有该单词的句子数
def n_containing(word, count_list):
    return sum(1 for count in count_list if word in count)


# len(count_list)是指句子的总数,n_containing(word, count_list)是指含有该单词的句子的总数,加1是为了防止分母为0
def idf(word, count_list):
    return math.log(len(count_list) / (1 + n_containing(word, count_list)))


# 将tf和idf相乘
def tf_idf(word, count, count_list):
    return tf(word, count) * idf(word, count_list)


for i, count in enumerate(count_list):
    print("Top words in document {}".format(i + 1))
    scores = {word: tf_idf(word, count, count_list) for word in count}
    sorted_words = sorted(scores.items(), key=lambda x: x[1], reverse=True)
    for word, score in sorted_words[:]:
        print("	Word: {}, TF-IDF: {}".format(word, round(score, 5)))
原文地址:https://www.cnblogs.com/selfcs/p/13201591.html