高端数据分析师,2019年数据分析师

  

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

  

  作者:小吴哥   

  

  来源:小吴歌谈风险控制   

  

  

一、了解tf-idf

  

  

  对于文本处理,tf-idf已经被广泛使用,在sklearn等知名的机器学习开源库中都提供了直接调用。但是很多人不知道TF-IDF是怎么计算的,所以无法改进这个计算方法。我之前也是糊里糊涂。在各种开源库一应俱全的Python时代,“谨慎换包”,所以我不能让自己成为一个只会换包的人。我们还是要修炼内功。在计算之前,我们先了解一下tf-idf的基本定义。   

  

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

  

  idf (inverse document frequency):反映了一个词在所有文本(整个文档).出现的频率,如果一个词出现在许多文本中,它的idf值应该较低,反之,如果一个词出现在少数文本中,它的idf值应该较高。   

  

  单词的重要性与它在文档中出现的次数成正比增加,但同时与它在语料库中出现的频率成反比减少。   

  

  我们来看看大多数情况下tf-idf的定义:   

  

  TF的计算公式如下:   

  

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

  

  在…之中   

  

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

  

  是词条w在某个文本中出现的次数,   

  

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

  

  是文本中条目的总数。   

  

  IDF的计算公式:   

img_width="640" img_height="169" inline="0" alt="万万没想到,TF-IDF是这么计算的" onerror="javascript:errorimg.call(this);">

其中Y是语料库的文档总数,Yw是包含词条w的文档数,分母加一是为了避免

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

未出现在任何文档中从而导致分母为

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

的情况。
TF-IDF的就是将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是这么计算的

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

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

和我们sklearn计算的

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

答案并不对,哪里出了问题呢?我们仔细看看原来的代码,因为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值了,加深了对该方法的理解,以便于后期的算法调用,心里有货,才不惧未知。

相关文章