TfidfVectorizer如何计算测试数据的分数

时间:2019-04-16 11:55:34

标签: scikit-learn nlp tf-idf tfidfvectorizer

在scikit-learn中,TfidfVectorizer使我们能够适应训练数据,并随后使用相同的矢量化器来转换我们的测试数据。 火车数据的转换输出是一个矩阵,代表给定文档中每个单词的tf-idf得分。

但是,拟合的矢量化器如何计算新输入的分数?我猜是这样的:

  1. 通过对训练集中的文档中相同单词的分数进行某种汇总,得出新文档中单词的分数。
  2. 将新文档“添加”到现有语料库并计算新分数。

我尝试从scikit-learn的来源code推论出该操作,但还不太清楚。它是我前面提到的选项之一还是其​​他所有选项? 请协助。

1 个答案:

答案 0 :(得分:1)

绝对是前者:每个单词的idf(反文档频率)仅基于培训文档来计算。这是有道理的,因为这些值正是您在矢量化器上调用fit时所计算的值。如果您描述的第二个选项是正确的,那么我们每次都会实质上重新设置矢量化程序,并且还会导致information leak,因为在模型评估期间会使用测试集中的idf。

除了这些纯粹的概念性解释之外,您还可以运行以下代码来说服自己:

from sklearn.feature_extraction.text import TfidfVectorizer
vect = TfidfVectorizer()
x_train = ["We love apples", "We really love bananas"]
vect.fit(x_train)
print(vect.get_feature_names())
>>> ['apples', 'bananas', 'love', 'really', 'we']

x_test = ["We really love pears"]

vectorized = vect.transform(x_test)
print(vectorized.toarray())
>>> array([[0.        , 0.        , 0.50154891, 0.70490949, 0.50154891]])

遵循适合方法的原理,您可以自己重新计算这些tfidf值:

“苹果”和“香蕉”的tfidf分数显然为0,因为它们未出现在x_test中。另一方面,{peas}在x_train中不存在,因此甚至不会出现在矢量化中。因此,只有“爱”,“真的”和“我们”才会有tfidf得分。

Scikit-learn将tfidf实现为log((1 + n)/(1 + df)+ 1)* f,其中n是训练集中的文档数(对我们来说是2),df是训练集中的文档数其中单词仅在训练集中出现 ,而f在测试集中的出现频率计数。因此:

tfidf_love = (np.log((1+2)/(1+2))+1)*1
tfidf_really = (np.log((1+2)/(1+1))+1)*1
tfidf_we = (np.log((1+2)/(1+2))+1)*1

然后,您需要根据文档的L2距离缩放这些tfidf分数:

tfidf_non_scaled = np.array([tfidf_love,tfidf_really,tfidf_we])
tfidf_list = tfidf_non_scaled/sum(tfidf_non_scaled**2)**0.5

print(tfidf_list)
>>> [0.50154891 0.70490949 0.50154891]

您可以看到,确实,我们得到了相同的值,这证实了scikit-learn实现此方法的方式。