为什么classifier.predict()方法要求测试数据的特征数量与训练数据相同?
我正在尝试使用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 个回答
在这种情况下,我们是否必须明确将测试数据的特征数量设置为9451?
是的,必须这样做。支持向量机(SVM)需要测试数据的维度和训练数据保持一致。人们在处理文档时,通常会使用“词袋”方法,或者选择前面x个不太常见的单词。
SVM(支持向量机)是一种机器学习方法,它的工作原理是把你的训练数据看作在一个n
维空间中,然后在这个数据集上进行一种几何优化。简单来说,如果n=2
,那么SVM就是在找一条线,这条线能最好地把(+)
的例子和(-)
的例子分开。
这意味着,训练一个SVM的结果是和它训练时的维度有关的。这个维度正好是你特征集合的大小(虽然还有一些其他的变换,但总的来说,这些信息共同决定了问题的空间)。所以,你不能把这个训练好的模型直接用在维度不同的新数据上。
(你可能会想,可以把训练空间投影或嵌入到测试空间中——在某些情况下这可能有效,但一般来说这是不正确的。)
不过,仔细分析后,这个情况会变得更加复杂。不仅测试数据的维度需要和训练数据的维度一致,而且每个维度的含义也必须保持不变。举个例子,在我们n=2
的例子中,假设我们要分类人们的情绪(快乐/悲伤),x
维度代表“生活的享受程度”,y
维度代表“听悲伤音乐的时间”。我们会期待更高的x
值和更低的y
值会提高快乐的可能性,因此SVM能找到的一个好的分界线就是y=x
这条线,因为靠近x
轴的人通常比较快乐,而靠近y
轴的人则比较悲伤。
但是,如果有人在放入测试数据时搞混了x
和y
的维度,那就糟糕了,预测结果会变得非常不准确。
所以特别要注意的是,测试数据的观察空间必须和训练数据的观察空间匹配。维度在这方面是一个重要的步骤,但这种匹配必须是完美的。
简单来说,你要么需要进行一些特征工程,要么找到一种没有这种依赖关系的算法(这也会涉及一些特征工程)。
为了确保你在特征表示上保持一致,你应该对测试数据进行转换,而不是重新拟合和转换。
x_train=vectorizer.fit_transform(f1)
x_test=vectorizer.transform(data2)
对你的标签也应该进行类似的转换,使其变得一致。