scikit-learn中的TfidfVectorizer如何计算TF-IDF

19

我运行以下代码将文本矩阵转换为TF-IDF矩阵。

text = ['This is a string','This is another string','TFIDF computation calculation','TfIDF is the product of TF and IDF']

from sklearn.feature_extraction.text import TfidfVectorizer
vectorizer = TfidfVectorizer(max_df=1.0, min_df=1, stop_words='english',norm = None)

X = vectorizer.fit_transform(text)
X_vovab = vectorizer.get_feature_names()
X_mat = X.todense()
X_idf = vectorizer.idf_

我得到了以下输出

X_vovab =

[u'calculation',
 u'computation',
 u'idf',
 u'product',
 u'string',
 u'tf',
 u'tfidf']

并且 X_mat =

  ([[ 0.        ,  0.        ,  0.        ,  0.        ,  1.51082562,
      0.        ,  0.        ],
    [ 0.        ,  0.        ,  0.        ,  0.        ,  1.51082562,
      0.        ,  0.        ],
    [ 1.91629073,  1.91629073,  0.        ,  0.        ,  0.        ,
      0.        ,  1.51082562],
    [ 0.        ,  0.        ,  1.91629073,  1.91629073,  0.        ,
      1.91629073,  1.51082562]])

现在我不明白这些分数是如何计算的。我的想法是,对于text [0],仅计算'string'的分数,并且存在第5列中的一个分数。但是,由于TF-IDF是词频乘以IDF的乘积(其中词频为2,IDF为log(4/2)),因此得出的结果应该是1.39而不是矩阵中显示的1.51。scikit-learn中如何计算TF-IDF分数。

3个回答

26

TF-IDF是由Scikit Learn的TfidfVectorizer完成的多个步骤,实际上使用了TfidfTransformer并继承了CountVectorizer。

  1. 通过CountVectorizer的fit_transform()计算tfs。
  2. 通过TfidfTransformer的fit()计算idfs。
  3. 通过TfidfTransformer的transform()计算tfidfs。

你可以在此处查看源代码。

回到你的例子。下面是针对词汇表中第5个术语,在第1个文档(X_mat [0,4])中计算tfidf权重的计算过程:

首先,计算第1个文档中“string”的tf:

tf = 1

其次,启用平滑(默认行为)后,'string'的idf值为:

df = 2
N = 4
idf = ln(N + 1 / df + 1) + 1 = ln (5 / 3) + 1 = 1.5108256238

最后,(文档0,特征4)的tfidf权重为:

tfidf(0,4) = tf * idf = 1 * 1.5108256238 = 1.5108256238

我注意到你选择不对tfidf矩阵进行归一化。需要记住的是,归一化tfidf矩阵是常见且通常推荐的方法,因为大多数模型需要特征矩阵(或设计矩阵)进行归一化。

TfidfVectorizer默认会对输出矩阵进行L-2归一化,作为计算的最后一步。这意味着它将只有0到1之间的权重。


2
这是非常好的答案!!我花了一整天来理解它。@Rabbit,你能在这个例子中展示一下如何应用归一化吗? - Himadri
很好的解释,这里有一个快速提示,sklearn使用的对数是自然对数,如果你手动推导(或使用计算器),请使用“ln”而不是以10为底的对数。 - cemsazara
@cemsazara,我已经修复了错误使用“log”而不是“ln”的部分,谢谢。 - Rabbit

6
精确的计算公式在文档中给出:
引用如下:
实际使用的tf-idf公式为 tf * (idf + 1) = tf + tf * idf,而不是 tf * idf。
另外,
通过将文档频率加一来平滑idf权重,就像看到包含集合中每个术语的一个额外文档。这意味着1.51082562是通过1+ln((4+1)/(2+1))获得的。

所以1.51仅代表IDF分数,而不是TF-IDF分数。我猜TF-IDF分数应该是2 * 1.51 = 3.02。 - prashanth
1
词频只有1,对吧?这就是为什么我们要乘以1*1.51。 - Christian Hirsch
现在我明白了。谢谢。 - prashanth

1
from sklearn.feature_extraction.text import CountVectorizer
from sklearn.feature_extraction.text import TfidfVectorizer
from collections import Counter
corpus = [
     'This is the first document.',
     'This document is the second document.',
     'And this is the third one.',
     'Is this the first document?',
 ]
print(corpus)
vectorizer = CountVectorizer()
X = vectorizer.fit_transform(corpus)
print(vectorizer.get_feature_names())

z=X.toarray()
#term frequency is printed
print(z)

vectorizer1 = TfidfVectorizer(min_df=1)
X1 = vectorizer1.fit_transform(corpus)
idf = vectorizer1.idf_
print (dict(zip(vectorizer1.get_feature_names(), idf)))
#printing idf
print(X1.toarray())
#printing tfidf

#formula 
# df = 2
# N = 4
# idf = ln(N + 1 / df + 1) + 1 = log (5 / 3) + 1 = 1.5108256238

#formula
# tfidf(0,4) = tf * idf = 1 * 1.5108256238 = 1.5108256238

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接