我正在尝试使用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 ?
为了确保您有相同的特征表示,您不应该对您的测试数据进行fit_transform,而应该只对它进行transform。
x_train=vectorizer.fit_transform(f1)
x_test=vectorizer.transform(data2)
类似的同质特征转换应该应用到你的标签上。
SVM的工作原理是假设你所有的训练数据都存在于一个n
维空间中,然后对该集合执行一种几何优化。为了使其具体化,如果n=2
,那么SVM将选择一条最佳地将(+)
示例与(-)
示例分开的线。
这意味着训练支持向量机的结果与它被训练的维度有关。这个维度正是特征集的大小(模核和其他转换,但在任何情况下,所有这些信息一起唯一地设置了问题空间)。因此,你不能仅仅将这个训练好的模型应用于存在于不同维度空间中的新数据。
(您可能会建议我们将训练空间投影或嵌入到测试空间中——这在某些情况下甚至可能有效——但通常是无效的。)
然而,当你真正分析它时,这种情况变得更加棘手。不仅测试数据维度需要与训练数据维度相对应,而且每个维度的意义需要是恒定的。例如,回到n=2
的例子,假设我们正在分类人们的情绪(快乐/悲伤),x
维度是"享受生活",y
维度是"花在听悲伤音乐上的时间"。我们期望x
值越大,y
值越小,幸福的可能性越大,所以SVM可以找到的一个很好的区分边界是y=x
线,因为靠近x
轴的人往往快乐,而靠近y
轴的人往往悲伤。
但是,假设有人在放入测试数据时混淆了x
和y
维度。突然之间,你得到了一个非常不准确的预测器。
所以特别地,测试数据的观测空间必须与训练数据的观测空间匹配。在这方面,维度是重要的一步,但匹配必须是完美的。
这是一个很长的说法,你需要做一些特征工程或找到一个没有这种依赖的算法(这也将涉及一些特征工程)。
在这种情况下,我们是否需要显式地将测试数据的特征个数设置为等于9451 ?
不,你有。支持向量机需要管理与训练集相同的维度。人们在处理文档时倾向于使用单词包的方法,或者选择前x个不太常见的单词。