【问题标题】:Dimensions different after performing the same preprocessing with CountVectorizer使用 CountVectorizer 执行相同的预处理后尺寸不同
【发布时间】:2021-05-21 14:03:30
【问题描述】:

我对我的测试和训练稀疏矩阵在执行相同的预处理后如何具有不同数量的特征感到困惑

这使我无法预测我的测试数据

def vectorizer(X):
    vectorizer = CountVectorizer(stop_words = 'english')
    vectorizer.fit(X)
    X = vectorizer.fit_transform(X)
    
    return X
other_features = ["n_steps", "n_ingredients"]
features = df_train[other_features]
test_features = df_test[other_features]

name = vectorizer(df_train.name)
steps = vectorizer(df_train.steps)
ingr = vectorizer(df_train.ingredients)


test_name = vectorizer(df_test.name)
test_steps = vectorizer(df_test.steps)
test_ingr = vectorizer(df_test.ingredients)

X = hstack([steps,ingr, name, np.array(features)])
X_test = hstack([test_steps, test_ingr, test_name, np.array(test_features)])
clf = LogisticRegression(C = 0.01, max_iter = 1000000, penalty = 'l2')
clf.fit(X, y)
predictions = clf.predict(X_test)

预测时出现的错误:

---------------------------------------------------------------------------
ValueError                                Traceback (most recent call last)
<ipython-input-40-1534a274c605> in <module>
----> 1 predictions = clf.predict(X_test)

/opt/anaconda3/lib/python3.8/site-packages/sklearn/linear_model/_base.py in predict(self, X)
    305             Predicted class label per sample.
    306         """
--> 307         scores = self.decision_function(X)
    308         if len(scores.shape) == 1:
    309             indices = (scores > 0).astype(np.int)

/opt/anaconda3/lib/python3.8/site-packages/sklearn/linear_model/_base.py in decision_function(self, X)
    284         n_features = self.coef_.shape[1]
    285         if X.shape[1] != n_features:
--> 286             raise ValueError("X has %d features per sample; expecting %d"
    287                              % (X.shape[1], n_features))
    288 

ValueError: X has 16417 features per sample; expecting 31765

【问题讨论】:

  • 您正在为您的训练和测试数据分别制作一个新的矢量化器。我不知道你为什么认为它不会有所不同。向量化然后拆分。
  • 训练和测试数据在不同的文件中,我必须在预测测试数据之前用训练数据训练模型

标签: python scikit-learn


【解决方案1】:

您必须对两个数据集使用相同的 CountVectorizer 实例。当您使用.fit_transform 方法时,转换器在内部存储它学习到的转换,以便以后可以重新应用。

在您的代码中,您不仅为每个数据集创建了一个新的CountVectorizer 实例,而且还对每个数据集进行了全新的训练。如果您将“测试”数据视为“样本外”数据(即您当前没有的数据)的近似值,您应该明白为什么按照您的方式做是没有意义的,这就是您得到无意义结果的原因。

正确的用法应该是这样的:

vectorizer = CountVectorizer(stop_words = 'english')
classifier = LogisticRegression(C = 0.01, max_iter = 1000000, penalty = 'l2')

x_train = vectorizer.fit_transform(data_train)
clf.fit(x_train, y_train)
pred_train = clf.predict(x_train)

x_test = vectorizer.transform(data_test)
pred_test = clf.predict(x_test)

请注意,在您的情况下,您可能还想使用PipelineColumnTransformer

我建议阅读this guide 了解更多信息。

【讨论】:

  • 您需要在具有不同特征的训练和测试数据上拟合矢量化器,否则转换测试数据不会捕获很多特征。
  • @CJR 这不是它的工作方式。如果该特征不在您的训练数据中,那么当它在预测时出现在样本外数据中时,您无法神奇地添加它,除非您在样本外数据上重新训练模型,此时指出它不再是“样本外”数据,也不再是“预测时间”。有一些技术可以解决这个问题(比如特征散列),但你不能假装问题不存在。
  • 训练数据中没有的特征对模型没有贡献(它们都是 0;没有方差的特征对预测没有用处)。你并没有神奇地添加任何东西。
  • @CJR 是的,您正在神奇地扩展您的词汇量。如果您事先有一个已知的词汇表,请使用它而不是从训练数据中推断出来。无论如何,这些 0 特征都应该得到 0 权重,在这种情况下,它们实际上什么也没做,甚至没有任何意义。
  • 您假设您刚才所说的内容很直观,并且训练模型的人已经知道它们。显然这不是真的,否则永远不会问这个问题。我可以想到几个很好的理由来对齐训练/测试特征(也许你想在你的测试和训练数据之间做一个相似性度量,如果它们不是拆分统一数据集的结果,这可能是一个有用的可视化)。这不是信息泄漏和有用的澄清。
【解决方案2】:

使用适合您的训练数据的矢量化器对您的测试数据进行矢量化。否则输入编码不一样,所以你的模型在第一个数据集上学到的任何东西都是无关紧要的。

至于为什么它的长度不同:当您适合矢量化器时,唯一(非排除)单词的数量变成了矢量的长度。如果一个或另一个中的单词仅在一个数据点中,则另一个数据点中将丢失该单词。所以两者的唯一词数量不同,它们最终的长度也不同。

所以 tl;博士。一次安装,使用两次。


count = CountVectorizer()
count.fit(X_train)
X_train_vec = count.transform(X_train)
X_test_vec = count.transform(Y_train)

如果你想自动化,你可以把它放在管道中。


pipeline = Pipeline(('count', CountVectorizer()),
                    ('model', [yourmodel])

# Regression predictions
Y_train = pipeline.fit_transform(X_train)
Y_test = pipeline.transform(X_test)

test_acc = metrics.accuracy(X_test, Y_test, Y_test_labels) # Or whatever metric

【讨论】:

    猜你喜欢
    • 2014-08-14
    • 1970-01-01
    • 2020-08-15
    • 2015-11-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-12-26
    相关资源
    最近更新 更多