使用保存的 sklearn 模型进行预测

Posted

技术标签:

【中文标题】使用保存的 sklearn 模型进行预测【英文标题】:using saved sklearn model to make prediction 【发布时间】:2018-12-27 10:29:31 【问题描述】:

我有一个已保存的逻辑回归模型,我使用训练数据进行了训练并使用 joblib 进行了保存。我正在尝试在不同的脚本中加载此模型,将新数据传递给它并根据新数据进行预测。

我收到以下错误“sklearn.exceptions.NotFittedError: CountVectorizer - Vocabulary was not fit.”我需要再次拟合数据吗?我原以为能够保存模型的意义在于不必这样做。

我使用的代码如下,不包括数据清理部分。任何有助于使预测发挥作用的帮助将不胜感激。

new_df = pd.DataFrame(latest_tweets,columns=['text'])
new_df.to_csv('new_tweet.csv',encoding='utf-8')
csv = 'new_tweet.csv'

latest_df = pd.read_csv(csv)
latest_df.dropna(inplace=True)
latest_df.reset_index(drop=True,inplace=True)
new_x = latest_df.text

loaded_model = joblib.load("finalized_mode.sav")

tfidf_transformer = TfidfTransformer()
cvec = CountVectorizer()
x_val_vec = cvec.transform(new_x)
X_val_tfidf = tfidf_transformer.transform(x_val_vec)

result = loaded_model.predict(X_val_tfidf)
print (result)

【问题讨论】:

【参考方案1】:

你还没有fit CountVectorizer。

你应该这样做..

cvec = CountVectorizer()
x_val_vec = cvec.fit_transform(new_x)

同样,TfidTransformer 也必须这样使用..

X_val_tfidf = tfidf_transformer.fit_transform(x_val_vec)

【讨论】:

谢谢,现在它说“result = loaded_model.predict(X_val_tfidf) AttributeError: 'CountVectorizer' object has no attribute 'predict'” 你确定文件finalized_mode.sav是训练好的模型吗?。它是根据错误保存的CountVectorizer 文件。确保正确保存经过训练的 LR 模型 谢谢你,我把它保存为 countvectorizer。修复该问题并再次运行后,我收到以下错误。 “ValueError:X 每个样本有 130 个特征;预期为 223086”。我只使用 1 个模型,所以不知道为什么会这样。 它表示该模型是在具有不同特征数量的数据集上训练的。您正在尝试预测具有不同特征的数据集。尝试打印用于训练模型的 X 形状和用于预测的 X 我预测的 x 形状是 (12,129)。对于训练,形状是 (1197030, 223086),我能够使用带有 (399011, 223086) 的测试集进行预测。从 csv 即时读取的列少了一列,整体条目少了很多,这就是形状不同的原因吗?【参考方案2】:

您的训练部分有 3 个适合数据的部分:

CountVectorizer:学习训练数据的词汇并返回计数

TfidfTransformer:从前一部分学习词汇的计数,并返回tfidf

LogisticRegression:学习特征系数以获得最佳分类性能。

由于每个部分都在学习有关数据的信息并使用它来输出转换后的数据,因此您需要在测试新数据时拥有所有 3 个部分。但是你只是用joblib保存lr,所以其他两个丢失了,训练数据词汇和计数也随之丢失。

现在在您的测试部分,您正在初始化新的CountVectorizerTfidfTransformer,并调用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)

【讨论】:

非常感谢您的详细回答,我非常感谢。我已经实现了使事情更容易阅读的管道,并且培训和测试正在发挥作用。我目前正在将完成的模型加载到另一个脚本中并输入原始文本,它正在给我预测。这是正确的吗?因为流水线,我不再需要 countvectorize 和 tdidf 了吗? @dmnte 是的。这些已经包含在管道中,因此被保存了。无需单独保存

以上是关于使用保存的 sklearn 模型进行预测的主要内容,如果未能解决你的问题,请参考以下文章

在 spark ML 2.2.0 中使用 sklearn-python 模型进行预测

sklearn训练模型的保存与加载

保存的 sklearn 模型的预测与训练过的模型不同

(sklearn)机器学习模型的保存与加载

如何在 Python 中使用 sklearn 对模型进行单一预测?

使用 Sklearn.naive_bayes.Bernoulli 的朴素贝叶斯分类器;如何使用模型进行预测?