3

我是向量空间模型(VSM)的初学者。我尝试了 这个站点的代码。这是对 VSM 的一个很好的介绍,但我设法从作者那里得到了不同的结果。这可能是因为一些兼容性问题,因为自编写介绍以来scikit learn似乎发生了很大变化。可能是我也误解了解释。
我使用下面的代码得到了错误的答案。有人能弄清楚它有什么问题吗?我在下面发布代码的结果和下面的正确答案

我已经手工完成了计算,所以我知道网站的结果很好。还有另一个Stackoverflow 问题使用相同的代码,但它也没有得到与网站相同的结果。

import numpy, scipy, sklearn

train_set = ("The sky is blue.","The sun is bright.")
test_set = ("The sun is the sky is bright.", "We can see the shining sun, the bright sun.")

from sklearn.feature_extraction.text import CountVectorizer
vectorizer = CountVectorizer(stop_words= 'english')

vectorizer.fit_transform(train_set)


smatrix = vectorizer.transform(test_set)


from sklearn.feature_extraction.text import TfidfTransformer


tfidf = TfidfTransformer(norm='l2', sublinear_tf=True)


tfidf.fit(smatrix)
#print smatrix.todense()
print tfidf.idf_

tf_idf_matrix = tfidf.transform(smatrix)
print tf_idf_matrix.todense()

tf-idf 的结果向量
#[ 2.09861229 1. 1.40546511 1. ]

tf-idf 的右向量
#[0.69314718, -0.40546511, -0.40546511, 0]

结果 tf_idf_matrix
#[[ 0. 0.50154891 0.70490949 0.50154891]
#[ 0. 0.50854232 0. 0.861037 ]]

正确答案
# [[ 0. -0.70710678 -0.70710678 0. ]
# [ 0. -0.89442719 -0.4472136 0. ]]

4

1 回答 1

4

这不是你的错,这是因为当前使用的公式sklearn与教程中使用的公式不同。

当前版本sklearn使用这个公式(source):

idf = log ( n_samples / df ) + 1

其中n_samples是指文档总数(|D|在教程中),df是指出现该术语的文档数({d:t_1 \in D}在教程中)。

为了处理零除法,它们默认使用平滑(选项smooth_idf=True中的选项TfidfVectorizer,请参阅文档)这样更改dfn_samples值,因此这些值至少为 1:

df += 1
n_samples += 1

虽然教程中的那个使用了这个公式:

idf = log ( n_samples / (1+df) )

因此,除非您更改源代码中的公式,否则您无法获得与教程中完全相同的结果。

编辑

严格来说,正确的公式是log(n_samples/df),但由于它在实践中会导致零除问题,人们试图修改公式以使其适用于所有情况。最常见的就是你说log(n_samples/(1+df))的: ,但是log(n_samples/df)+1考虑到你已经事先平滑了它,使用公式也没有错。但是阅读代码历史,似乎他们这样做是为了不会有负的 IDF 值(如本拉取请求中所述,稍后在本修复中更新)。另一种去除负 IDF 值的方法是将负值转换为 0。我还没有找到哪个是更常用的方法。

他们确实同意他们这样做的方式不是标准方式。所以你可以肯定地说这log(n_samples/(1+df))是正确的方法。

要编辑公式,首先我必须警告您这将影响使用该代码的每个用户,请确保您知道自己在做什么。

您可以直接转到源代码(在 Unix 中:位于/usr/local/lib/python2.7/dist-packages/sklearn/feature_extraction/text.py,在 Windows 中:我现在不使用 Windows,但您可以搜索文件“text.py”)并直接编辑公式。您可能需要管理员/root 访问权限,具体取决于您使用的平台。

附加说明

作为附加说明,词汇表中的术语顺序也不同(至少在我的机器中),因此要获得完全相同的结果(如果公式相同),您还需要传入完全相同的词汇表在教程中显示。所以使用你的代码:

vocabulary = {'blue':0, 'sun':1, 'bright':2, 'sky':3}
vectorizer = CountVectorizer(vocabulary=vocabulary) # You don't need stop_words if you use vocabulary
vectorizer.fit_transform(train_set)
print 'Vocabulary:', vectorizer.vocabulary_
# Vocabulary: {'blue': 0, 'sun': 1, 'bright': 2, 'sky': 3}
于 2013-09-09T06:25:36.713 回答