为啥 classifier.predict() 方法期望测试数据中的特征数量与训练数据中的相同?
Posted
技术标签:
【中文标题】为啥 classifier.predict() 方法期望测试数据中的特征数量与训练数据中的相同?【英文标题】:Why does classifier.predict() method expects the number of features in the test data to be the same as in training data?为什么 classifier.predict() 方法期望测试数据中的特征数量与训练数据中的相同? 【发布时间】:2014-04-30 04:23:02 【问题描述】:我正在尝试使用 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?
【问题讨论】:
Scikit learn - Random Forest Classifier 和几个之前的问题可能重复。 @larsmans “几个较早的问题” ....喜欢吗?您确实提到的一个问题导致了其中一个恰好与此相同的答案,但 OP 描述的问题不同。相同的答案并不意味着问题相同。 我找不到那些早先的问题,但我知道我之前给出的答案是“使用transform
,而不是fit_transform
”。问题实际上是相同的,在测试集上使用fit_transform
。
@larsmans 在标记为重复时提及您已回答的问题,或者停止标记其他人的问题。
Here's one,虽然我没有具体回答。您似乎将此视为人身攻击,但事实并非如此。
【参考方案1】:
在这种情况下,我们是否必须将测试数据的特征数显式设置为等于 9451?
是的,你知道。 SVM 需要管理与训练集相同的维度。人们在处理文档时倾向于使用词袋方法或选择前 x 个不太常见的词。
【讨论】:
【参考方案2】:为确保您具有相同的特征表示,您不应 fit_transform 测试数据,而应仅对其进行转换。
x_train=vectorizer.fit_transform(f1)
x_test=vectorizer.transform(data2)
应将类似的转换为同质特征应用于您的标签。
【讨论】:
为这个答案添加一些概念上的理解:测试是应该与训练集具有相同数量的特征;其中没有出现的单词的值为零。【参考方案3】:SVM 的工作原理是假设您的所有训练数据都位于 n
维空间中,然后对该数据集执行某种几何优化。具体来说,如果 n=2
则 SVM 将选择一条线,以最佳方式将 (+)
示例与 (-)
示例分开。
这意味着训练 SVM 的结果与训练它的维度相关联。这个维度正是您的特征集的大小(模核和其他转换,但无论如何所有这些信息加在一起)唯一地设置问题空间)。因此,您不能只将这个经过训练的模型应用于存在于不同维度空间中的新数据。
(您可能会建议我们将训练空间投影或嵌入到测试空间中——这在某些情况下甚至可能有效——但它通常是无效的。)
但是,当您真正分析它时,这种情况会变得更加棘手。不仅测试数据维度需要与训练数据维度对应,而且每个维度的含义也需要保持不变。例如,回到我们的n=2
示例,假设我们正在对人们的情绪(快乐/悲伤)进行分类,x
维度是“享受生活”,y
维度是“听悲伤音乐所花费的时间”。我们预计较大的x
和较小的y
值会提高幸福的可能性,因此SVM 可以找到的良好区分边界将是y=x
线,因为接近x
轴的人往往是快乐且更接近y
轴往往会感到悲伤。
但是,假设有人在放入测试数据时弄混了x
和y
维度。砰,突然之间,你得到了一个非常不准确的预测器。
所以特别是,测试数据的观察空间必须匹配训练数据的观察空间。维度是这方面的重要一步,但实际上必须是完美的匹配。
说你需要做一些特征工程或者找到一个没有这种依赖关系的算法(这也将涉及一些特征工程)。
【讨论】:
以上是关于为啥 classifier.predict() 方法期望测试数据中的特征数量与训练数据中的相同?的主要内容,如果未能解决你的问题,请参考以下文章
为啥 MonthCalendar 在 3rd 方应用程序中看起来不同?