使用scikit-learn和手工计算得出的tf-idf矩阵值的差异

8

我正在使用scikit-learn来查找tf-idf值。

我有一组像这样的文档:

D1 = "The sky is blue."
D2 = "The sun is bright."
D3 = "The sun in the sky is bright."

我想创建一个类似这样的矩阵:
   Docs      blue    bright       sky       sun
   D1 tf-idf 0.0000000 tf-idf 0.0000000
   D2 0.0000000 tf-idf 0.0000000 tf-idf
   D3 0.0000000 tf-idf tf-idf tf-idf

所以,我的 Python 代码如下:
import nltk
import string

from sklearn.feature_extraction.text import TfidfVectorizer
from nltk.corpus import stopwords

train_set = ["sky is blue", "sun is bright", "sun in the sky is bright"]
stop_words = stopwords.words('english')

transformer = TfidfVectorizer(stop_words=stop_words)

t1 = transformer.fit_transform(train_set).todense()
print t1

我得到的结果矩阵是:
[[ 0.79596054  0.          0.60534851  0.        ]
 [ 0.          0.4472136   0.          0.89442719]
 [ 0.          0.57735027  0.57735027  0.57735027]]

如果我进行手算,那么矩阵应该是这样的:
            Docs  blue      bright       sky       sun
            D1    0.2385    0.0000000  0.0880    0.0000000
            D2    0.0000000 0.0880     0.0000000 0.0880
            D3    0.0000000 0.058      0.058     0.058 

我正在计算,例如将blue作为tf = 1/2 = 0.5,并将idf作为log(3/1) = 0.477121255。因此,tf-idf = tf*idf = 0.5*0.477 = 0.2385。我正在以这种方式计算其他tf-idf值。现在,我想知道为什么在手动计算的矩阵和Python计算的矩阵中得到不同的结果?哪个可以给出正确的结果?是我手动计算有误还是我的Python代码有误?
2个回答

14

有两个原因:

  1. 您忽略了在这种情况下经常发生的平滑
  2. 您假设以10为底数的对数。

根据源代码,scikit-learn不使用这样的假设。

首先,它会平滑文档计数(因此从不出现0):

df += int(self.smooth_idf)
n_samples += int(self.smooth_idf)

它使用自然对数 (np.log(np.e)==1)

idf = np.log(float(n_samples) / df) + 1.0

此外,还应用默认的l2归一化。简而言之,在计算tf-idf时,scikit-learn做了很多“好的小事情”。它们和你使用的方法都不错,只是它们更为先进。


我在想为什么比率的差异是不同的。两个矩阵中所有值的差异不能用任何乘法或除法表示。 - user2481422
我的答案也为你提供了这个问题的答案。平滑不仅仅是“不同的乘法”,在idf部分使用不同的对数底数也是如此。 - lejlot

0
smooth_idf:布尔型,默认值为True。使用平滑过的idf。有许多版本。在Python中,使用以下版本:$1+log((N+1)/n+1))$,其中$N$是文档总数,$n$是包含该术语的文档数。
tf : 1/2, 1/2
idf with smoothing: (log(4/2)+1) ,(log(4/3)+1)
tf-idf : 1/2* (log(4/2)+1) ,1/2 * (log(4/3)+1)
L-2 normalization: 0.79596054 0.60534851

顺便说一下,原问题中的第二个可能是错误的,应该是相同的。 我的Python输出


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