万万没想到,TF-IDF是这么计算的!

AI入门学习

共 3455字,需浏览 7分钟

 ·

2022-03-16 08:25

一、了解tf-idf

对于文本处理,tf-idf的使用已经非常普遍,在sklearn等知名的机器学习开源库中都提供了直接的调用,然而很多人并没有搞清楚TF-IDF是怎么算出来的,也就无法对这种计算方法进行针对性的改进了。我之前也是稀里糊涂的,在各种开源库随手可得的Python年代“调包需谨慎”,不能让自己成为只会调包的人,我们内功还是需要修炼的,计算之前,我们先了解下tf-idf的基本定义。

tf(term frequency:指的是某一个给定的词语在该文件中出现的次数,这个数字通常会被归一化(一般是词频除以该文件总词数),以防止它偏向长的文件。

idf (inverse document frequency):反应了一个词在所有文本(整个文档)中出现的频率,如果一个词在很多的文本中出现,那么它的idf值应该低,而反过来如果一个词在比较少的文本中出现,那么它的idf值应该高。
一个词语的重要性随着它在文件中出现的次数成正比增加,但同时会随着它在语料库中出现的频率成反比下降。

下面我们看看大多数情况下,tf-idf 的定义:
TF的计算公式如下:

其中是在某一文本中词条w出现的次数,是该文本总词条数。

IDF的计算公式:

其中Y是语料库的文档总数,Yw是包含词条w的文档数,分母加一是为了避免未出现在任何文档中从而导致分母为的情况。
TF-IDF的就是将TF和IDF相乘

从以上计算公式便可以看出,某一特定文件内的高词语频率,以及该词语在整个文件集合中的低文件频率,可以产生出高权重的TF-IDF。因此,TF-IDF倾向于过滤掉常见的词语,保留重要的词语。

二、手算tf-idf

现在我们来看看,tf-idf到底怎么计算的,和我们手算的能不能对上。

在sklearn中,tf与上述定义一致,我们看看idf在sklearn中的定义,可以看到,分子分母都加了1,做了更多的平滑处理

smooth_idf=False

idf(t) = log [ n / df(t) ] + 1

smooth_idf=True

idf(t) = log [ (1 + n) / (1 + df(t)) ] + 1

下面我们手把手的计算出TF-IDF的值,使用的是sklearn官方的案例:

corpus = ['This is the first document.',                     'This document is the second document.',                     'And this is the third one.',                     'Is this the first document?'] #初始化 vector = TfidfVectorizer()
#tf-idf计算 tfidf = vector.fit_transform(corpus)
#直接打印,得到的是一个稀疏矩阵,第1位表示文档编号,第二位代表词的编号 print(tfidf) (0, 1) 0.46979138557992045 (0, 2) 0.5802858236844359 (0, 6) 0.38408524091481483 (0, 3) 0.38408524091481483 (0, 8) 0.38408524091481483 (1, 5) 0.5386476208856763 (1, 1) 0.6876235979836938 (1, 6) 0.281088674033753 (1, 3) 0.281088674033753 (1, 8) 0.281088674033753 (2, 4) 0.511848512707169 (2, 7) 0.511848512707169 (2, 0) 0.511848512707169 (2, 6) 0.267103787642168 (2, 3) 0.267103787642168 (2, 8) 0.267103787642168 (3, 1) 0.46979138557992045 (3, 2) 0.5802858236844359 (3, 6) 0.38408524091481483 (3, 3) 0.38408524091481483 (3, 8) 0.38408524091481483

通过vocabulary_属性,可以查看每个词对应的数字编号,就可以与上面的矩阵对应起来了

vector.vocabulary_ {'this': 8,  'is': 3,  'the': 6,  'first': 2,  'document': 1, 'second': 5,  'and': 0,  'third': 7,  'one': 4}

通过上面的字典和矩阵可以知道,第一个文档'This is the first document'的tf-idf 值如下

(0, 1)  0.46979138557992045 document(0, 2)  0.58028582368443590 first(0, 6)  0.38408524091481483 the(0, 3)  0.38408524091481483 is(0, 8)  0.38408524091481483 this

document   first           the             is             this

0.46979      0.58028      0.384085   0.38408  0.384085


我们手动计算来验证下:

tf 计算

对于第一个文档,有5个不同的词,每个词的词频为:tf= 1/5


idf计算

document:log((1+N)/(1+N(document)))+1=  log((1+4)/(1+3))+1 = 1.2231435first   :log((1+N)/(1+N(first)))+1   =  log((1+4)/(1+2))+1 = 1.5108256the     :log((1+N)/(1+N(the )))+1    =  log((1+4)/(1+4))+1 = 1.0is      :log((1+N)/(1+N(is )))+1     =  log((1+4)/(1+4))+1 = 1.0this    :log((1+N)/(1+N(this)))+1    =  log((1+4)/(1+4))+1 = 1.0


tf-idf计算

1.2231435*1/5 = 0.244628691.5108256*1/5 = 0.302165121.0*1/5 = 0.21.0*1/5 = 0.21.0*1/5 = 0.2

得到我们手工计算的tf-idf

和我们sklearn计算的

答案并不对,哪里出了问题呢?我们仔细看看原来的代码,因为sklearn做了归一化,我们按同样的方法进行归一化计算如下:

计算每个tf-idf 的平方根

(0.24462869**2 + 0.30216512**2 + 0.2**2 + 0.2**2 + 0.2**2)**0.5 = 0.5207177313


对每个值除以平方根

0.24462869/0.5207177313244965 = 0.46979135774340350.30216512/0.5207177313244965 = 0.58028582823829230.20000000/0.5207177313244965 = 0.38408524997080550.20000000/0.5207177313244965 = 0.38408524997080550.20000000/0.5207177313244965 = 0.3840852499708055

这样一看,就和我们的sklearn计算的一致了,到此,我们也算是学会了计算tf-idf值了,加深了对该方法的理解,以便于后期的算法调用,心里有货,才不惧未知。

浏览 169
点赞
评论
收藏
分享

手机扫一扫分享

分享
举报
评论
图片
表情
推荐
点赞
评论
收藏
分享

手机扫一扫分享

分享
举报