- 我已经训练了一个机器学习模型,并将其存储为Pickle文件。
- 在我的新脚本中,我正在读取新的“现实世界数据”,我想对其进行预测。
然而,我遇到了困难。我有一个包含字符串值的列,例如:
Sex Male Female# 这只是一个例子,实际上它有更多的唯一值
现在问题来了。我接收到一个新的(唯一)值,现在我无法再进行预测(例如,添加了'Neutral'
)。
因为我将'Sex'
列转换为虚拟变量,所以我的模型不再接受输入,
模型的特征数必须与输入匹配。模型的特征数为2,而输入的特征数为3
因此我的问题是:有没有办法使我的模型更加健壮,并且可以忽略这个类?但仍然可以进行预测,不需要特定的信息?
我尝试过的方法:
df = pd.read_csv('dataset_that_i_want_to_predict.csv')model = pickle.load(open("model_trained.sav", 'rb'))# 我有一个'example_df',仅包含一行训练数据(这正是模型所需的)example_df = pd.read_csv('reading_one_row_of_trainings_data.csv')# 检查缺少的列,并将这些列添加到新的数据集中 missing_cols = set(example_df.columns) - set(df.columns)for column in missing_cols: df[column] = 0 #添加缺少的列,值为0(这是可以的,因为所有都是虚拟变量)# 确保我们有相同的顺序 df = df[example_df.columns] # 预测将导致错误!results = model.predict(df)# ValueError: 模型的特征数必须与输入匹配。模型的特征数为X,而特征数为Y
注意,我搜索过,但找不到任何有帮助的解决方案(不是这里,这里或这里)
更新
还找到了这篇文章。但这里也有同样的问题…我们可以使测试集具有与训练集相同的列…但是新的现实世界数据(例如,新值’Neutral’)怎么办?
回答:
是的,在训练部分完成后,你不能在数据集中包含(更新模型)新的类别或特征。OneHotEncoder
可以处理测试数据中某些特征的新类别问题。它将确保在训练和测试数据中保持与分类变量相关的列的一致性。
from sklearn.compose import ColumnTransformerfrom sklearn.pipeline import Pipelinefrom sklearn.linear_model import LogisticRegressionfrom sklearn.preprocessing import OneHotEncoderimport numpy as npimport pandas as pdfrom sklearn import set_configset_config(print_changed_only=True)df = pd.DataFrame({'feature_1': np.random.rand(20), 'feature_2': np.random.choice(['male', 'female'], (20,))})target = pd.Series(np.random.choice(['yes', 'no'], (20,)))model = Pipeline([('preprocess', ColumnTransformer([('ohe', OneHotEncoder(handle_unknown='ignore'), [1])], remainder='passthrough')), ('lr', LogisticRegression())])model.fit(df, target)# 让我们在测试数据的feature_2中引入新类别test_df = pd.DataFrame({'feature_1': np.random.rand(20), 'feature_2': np.random.choice(['male', 'female', 'neutral', 'unknown'], (20,))})model.predict(test_df)# array(['yes', 'yes', 'yes', 'yes', 'yes', 'yes', 'yes', 'yes', 'yes',# 'yes', 'yes', 'yes', 'yes', 'yes', 'yes', 'yes', 'yes', 'yes',# 'yes', 'yes'], dtype=object)