您的训练部分有 3 个适合数据的部分:
CountVectorizer:学习训练数据的词汇并返回计数
TfidfTransformer:从前一部分学习词汇的计数,并返回tfidf
LogisticRegression:学习特征系数以获得最佳分类性能。
由于每个部分都在学习有关数据的信息并使用它来输出转换后的数据,因此您需要在测试新数据时拥有所有 3 个部分。但是你只是用joblib保存lr,所以其他两个丢失了,训练数据词汇和计数也随之丢失。
现在在您的测试部分,您正在初始化新的CountVectorizer 和TfidfTransformer,并调用fit() (fit_transform()),它将仅从这些新数据中学习词汇。所以单词会比训练单词少。但随后您加载了之前保存的 LR 模型,该模型根据训练数据等特征期望数据。因此出现此错误:
ValueError: X has 130 features per sample; expecting 223086
你需要做的是:
训练期间:
filename = 'finalized_model.sav'
joblib.dump(lr, filename)
filename = 'finalized_countvectorizer.sav'
joblib.dump(cvec, filename)
filename = 'finalized_tfidftransformer.sav'
joblib.dump(tfidf_transformer, filename)
测试期间
loaded_model = joblib.load("finalized_model.sav")
loaded_cvec = joblib.load("finalized_countvectorizer.sav")
loaded_tfidf_transformer = joblib.load("finalized_tfidftransformer.sav")
# Observe that I only use transform(), not fit_transform()
x_val_vec = loaded_cvec.transform(new_x)
X_val_tfidf = loaded_tfidf_transformer.transform(x_val_vec)
result = loaded_model.predict(X_val_tfidf)
现在你不会得到那个错误了。
建议:
您应该使用TfidfVectorizer 代替 CountVectorizer 和 TfidfTransformer,这样您就不必一直使用两个对象。
除此之外,您还应该使用 Pipeline 将这两个步骤结合起来:- TfidfVectorizer 和 LogisticRegression,这样您只需使用单个对象(更易于保存和加载以及通用处理)。
所以像这样编辑训练部分:
tfidf_vectorizer = TfidfVectorizer()
lr = LogisticRegression()
tfidf_lr_pipe = Pipeline([('tfidf', tfidf_vectorizer), ('lr', lr)])
# Internally your X_train will be automatically converted to tfidf
# and that will be passed to lr
tfidf_lr_pipe.fit(X_train, y_train)
# Similarly here only transform() will be called internally for tfidfvectorizer
# And that data will be passed to lr.predict()
y_preds = tfidf_lr_pipe.predict(x_test)
# Now you can save this pipeline alone (which will save all its internal parts)
filename = 'finalized_model.sav'
joblib.dump(tfidf_lr_pipe, filename)
在测试期间,执行以下操作:
loaded_pipe = joblib.load("finalized_model.sav")
result = loaded_model.predict(new_x)