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

4 投票
3 回答
12091 浏览
提问于 2025-04-17 23:27

我正在尝试使用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?

3 个回答

0

在这种情况下,我们是否必须明确将测试数据的特征数量设置为9451?

是的,必须这样做。支持向量机(SVM)需要测试数据的维度和训练数据保持一致。人们在处理文档时,通常会使用“词袋”方法,或者选择前面x个不太常见的单词。

4

SVM(支持向量机)是一种机器学习方法,它的工作原理是把你的训练数据看作在一个n维空间中,然后在这个数据集上进行一种几何优化。简单来说,如果n=2,那么SVM就是在找一条线,这条线能最好地把(+)的例子和(-)的例子分开。

这意味着,训练一个SVM的结果是和它训练时的维度有关的。这个维度正好是你特征集合的大小(虽然还有一些其他的变换,但总的来说,这些信息共同决定了问题的空间)。所以,你不能把这个训练好的模型直接用在维度不同的新数据上。

(你可能会想,可以把训练空间投影或嵌入到测试空间中——在某些情况下这可能有效,但一般来说这是不正确的。)

不过,仔细分析后,这个情况会变得更加复杂。不仅测试数据的维度需要和训练数据的维度一致,而且每个维度的含义也必须保持不变。举个例子,在我们n=2的例子中,假设我们要分类人们的情绪(快乐/悲伤),x维度代表“生活的享受程度”,y维度代表“听悲伤音乐的时间”。我们会期待更高的x值和更低的y值会提高快乐的可能性,因此SVM能找到的一个好的分界线就是y=x这条线,因为靠近x轴的人通常比较快乐,而靠近y轴的人则比较悲伤。

但是,如果有人在放入测试数据时搞混了xy的维度,那就糟糕了,预测结果会变得非常不准确。


所以特别要注意的是,测试数据的观察空间必须和训练数据的观察空间匹配。维度在这方面是一个重要的步骤,但这种匹配必须是完美的。

简单来说,你要么需要进行一些特征工程,要么找到一种没有这种依赖关系的算法(这也会涉及一些特征工程)。

15

为了确保你在特征表示上保持一致,你应该对测试数据进行转换,而不是重新拟合和转换。

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

对你的标签也应该进行类似的转换,使其变得一致。

撰写回答