TF-IDF


算法介绍

TF-IDF(term frequency–inverse document frequency,词频-逆向文件频率)是一种用于信息检索(information retrieval)与文本挖掘(text mining)的常用 加权技术。

TF-IDF是一种统计方法,用以评估一字词对于一个文件集或一个语料库中的其中一份文件的重要程度。字词的重要性随着它在文件中出现的次数成正比增加,但同时会随着它在语料库中出现的频率成反比下降。

TF-IDF的主要思想是:如果某个单词在一篇文章中出现的频率TF高,并且在其他文章中很少出现,则认为此词或者短语具有很好的类别区分能力,适合用来分类。

TF

TF(Term Frequency, 词频) 表示词条在文本中出现的频率,这个数字通常会被归一化(一般是词频除以文章总词数) , 以防止它偏向长的文件(同一个词语在长文件里可能会比短文件有更高的词频,而不管该词语重要与否)。TF用公式表示如下

\(TF_{i,j}表示词条t_i在文档d_j中出现的频率\)\(n表示次数\)

但是,需要注意, 一些通用的词语对于主题并没有太大的作用, 反倒是一些出现频率较少的词才能够表达文章的主题, 所以单纯使用是TF不合适的。权重的设计必须满足:一个词预测主题的能力越强,权重越大,反之,权重越小。所有统计的文章中,一些词只是在其中很少几篇文章中出现,那么这样的词对文章的主题的作用很大,这些词的权重应该设计的较大。IDF就是在完成这样的工作。

在文档 ![ 中出现的频率。

IDF

IDF(Inverse Document Frequency, 逆文件频率) 表示关键词的普遍程度。

如果包含词条 的文档越少, IDF越大,则说明该词条具有很好的类别区分能力。某一特定词语的IDF,可以由总文件数目除以包含该词语之文件的数目,再将得到的商取对数得到

\(|D|\)表示所有文档的数量,\(|j:t_i\in d_j|\)表示包含词条\(t_i\)的文档数量

其中, 表示所有文档的数量, 表示包含词条 的文档数量,为什么这里要加 1 呢?主要是防止包含词条 的数量为 0 从而导致运算出错的现象发生

补充说明:从上面可以看到,对于不同的文档而言,同一个词条的TF-IDF值是不同的。TF和文档还有词有关,IDF和文档无关了(序号只含有i)。

TF就像是在自己这出现的多,IDF在说在别人那出现的很少,自然TF-IDF越大,该词对文章的重要性越大。

\(TF-IDF = TF*IDF\)

python实现

手动实现

corpus = ['this is the first document',
        'this is the second second document',
        'and the third one',
        'is this the first document']
words_list = list()
for i in range(len(corpus)):
    words_list.append(corpus[i].split(' '))
print(words_list)
[['this', 'is', 'the', 'first', 'document'], 
['this', 'is', 'the', 'second', 'second', 'document'], 
['and', 'the', 'third', 'one'], 
['is', 'this', 'the', 'first', 'document']]

from collections import Counter
count_list = list()
for i in range(len(words_list)):
    count = Counter(words_list[i])
    count_list.append(count)
print(count_list)
[Counter({'this': 1, 'is': 1, 'the': 1, 'first': 1, 'document': 1}), 
Counter({'second': 2, 'this': 1, 'is': 1, 'the': 1, 'document': 1}), 
Counter({'and': 1, 'the': 1, 'third': 1, 'one': 1}), 
Counter({'is': 1, 'this': 1, 'the': 1, 'first': 1, 'document': 1})]

import math
def tf(word, count):
    return count[word] / sum(count.values())


def idf(word, count_list):
    n_contain = sum([1 for count in count_list if word in count])
    return math.log(len(count_list) / (1 + n_contain))


def tf_idf(word, count, count_list):
    return tf(word, count) * idf(word, count_list)
    
for i, count in enumerate(count_list):
    print("第 {} 个文档 TF-IDF 统计信息".format(i + 1))
    scores = {word : tf_idf(word, count, count_list) for word in count}
    sorted_word = sorted(scores.items(), key = lambda x : x[1], reverse=True)
    for word, score in sorted_word:
        print("\tword: {}, TF-IDF: {}".format(word, round(score, 5)))
   

使用sklearn

from sklearn.feature_extraction.text import TfidfVectorizer
tfidf_vec = TfidfVectorizer()
tfidf_matrix = tfidf_vec.fit_transform(corpus)
# 得到语料库所有不重复的词
print(tfidf_vec.get_feature_names())
# 得到每个单词对应的id值
print(tfidf_vec.vocabulary_)
# 得到每个句子所对应的向量,向量里数字的顺序是按照词语的id顺序来的
print(tfidf_matrix.toarray())

参考

  • TF-IDF算法介绍及实现_Asia-Lee-CSDN博客

  • TF-IDF 原理与实现 - 知乎 (zhihu.com)