分类器.predict()方法为什么要求测试数据中的特征数量与训练数据相同?

4

我正在尝试使用scikit-learn构建一个简单的SVM文档分类器,我正在使用以下代码:

import os

import numpy as np

import scipy.sparse as sp

from sklearn.metrics import accuracy_score

from sklearn import svm

from sklearn.metrics import classification_report

from sklearn.feature_extraction.text import CountVectorizer

from sklearn.feature_extraction.text import TfidfTransformer

from sklearn.feature_extraction.text import TfidfVectorizer

from sklearn import cross_validation
from sklearn.datasets import load_svmlight_file

clf=svm.SVC()

path="C:\\Python27"


f1=[]

f2=[]
data2=['omg this is not a ship lol']

f=open(path+'\\mydata\\ACQ\\acqtot','r')

f=f.read()

f1=f.split(';',1085)

for i in range(0,1086):

    f2.append('acq')



f1.append('shipping ship')

f2.append('crude')    

from sklearn.feature_extraction.text import TfidfVectorizer

vectorizer = TfidfVectorizer(min_df=1)
counter = CountVectorizer(min_df=1)


x_train=vectorizer.fit_transform(f1)
x_test=vectorizer.fit_transform(data2)

num_sample,num_features=x_train.shape

test_sample,test_features=x_test.shape

print("#samples: %d, #features: %d" % (num_sample, num_features)) #samples: 5, #features: 25
print("#samples: %d, #features: %d" % (test_sample, test_features))#samples: 2, #features: 37

y=['acq','crude']

#print x_test.n_features

clf.fit(x_train,f2)


#den= clf.score(x_test,y)
clf.predict(x_test)

它会返回以下错误信息:
(n_features, self.shape_fit_[1]))
ValueError: X.shape[1] = 6 should be equal to 9451, the number of features at training time

但我不明白的是为什么它要求特征数量相同?如果我向机器输入全新的文本数据进行预测,显然不可能每个文档都与用于训练的数据具有相同数量的特征。在这种情况下,我们是否需要明确设置测试数据的特征数量等于9451?


@larsmans "几个早期的问题"....像什么?而且你提到的那个问题导致了一个答案,恰好与这个答案相同,但是OP描述的问题是不同的。相同的答案并不意味着问题相同。 - finitenessofinfinity
我找不到之前的那些问题,但我知道我以前给出过答案:“使用transform而不是fit_transform”。问题实际上是一样的,在测试集上使用fit_transform - Fred Foo
@larsmans,要么在标记为重复时提及您已回答过的那些问题,要么停止四处标记其他人的问题。 - finitenessofinfinity
@larsmans 你之前就可以提到这个啊。谢谢。我不会把它当做个人问题,只是我在这里见过一些非常狂热的人,他们喜欢四处标记问题,而不提供任何解释。再次感谢。 - finitenessofinfinity
这只是因为我不得不在这个网站上搜索,而这实在是很痛苦的,但你说得对,我应该证明我的说法。对此我感到抱歉。我试图避免有关scikit-learn的重复问题/答案,因为至少将问题链接起来可以更容易地找到它们 :) - Fred Foo
显示剩余2条评论
3个回答

15
为了确保您具有相同的功能表示,您不应该使用fit_transform来拟合和转换测试数据,而只需使用transform进行转换。
x_train=vectorizer.fit_transform(f1)
x_test=vectorizer.transform(data2)

你的标签也应该进行类似的转换,变成同质化的特征。


3
为了使回答更容易理解,这里加入一些概念性的解释:测试集应该与训练集具有相同数量的特征;在其中不出现的单词将被赋值为零。 - Fred Foo

3
SVM工作原理是假设所有的训练数据都存在于一个n维空间中,然后对这个集合进行一种几何优化。具体来说,如果n=2,则SVM会选择一条线将+示例和-示例最佳地分开。
这意味着训练SVM的结果与其所训练的维数密切相关。这个维数恰好等于你的特征集的大小(模除核函数和其他转换,但无论如何,所有这些信息加在一起都可以唯一地设置问题空间)。因此,你不能仅仅将这个训练好的模型应用到处于不同维度空间的新数据上。
然而,当你真正分析这种情况时,它变得更加棘手。测试数据的维数不仅需要与训练数据的维数相对应,而且每个维度的含义也需要保持恒定。例如,在我们的n=2的例子中,假设我们正在分类人们的心情(高兴/难过),x维是“生活享受”,y维是“听悲伤音乐花费的时间”。我们期望更大的x值和较小的y值有助于提高高兴的可能性,因此SVM可以找到一个好的判别边界,即y=x的线,因为靠近x轴的人倾向于高兴,靠近y轴的人倾向于难过。
但是,让我们假设有人在放入测试数据时混淆了x和y维度。瞬间,你就会得到一个极不准确的预测器。
因此,特别是测试数据的观察空间必须与训练数据的观察空间匹配。维数在这方面起着重要作用,但匹配实际上必须是完美的。
也就是说,你需要进行一些特征工程或找到一种没有这种依赖性的算法(这也将涉及一些特征工程)。

0
我们在这种情况下是否必须明确设置测试数据的特征数等于9451?
是的,必须这样做。SVM需要管理与训练集相同的维度。当处理文档时,人们倾向于使用词袋方法或选择前x个不常见的单词。

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