我们能否通过接受(或忽略)新特性使 ML 模型(pickle 文件)更加健壮?

Posted

技术标签:

【中文标题】我们能否通过接受(或忽略)新特性使 ML 模型(pickle 文件)更加健壮?【英文标题】:Can we make the ML model (pickle file) more robust, by accepting (or ignoring) new features? 【发布时间】:2021-03-02 18:06:16 【问题描述】: 我已经训练了一个 ML 模型,并将其存储到 Pickle 文件中。 在我的新脚本中,我正在阅读新的“真实世界数据”,我想对其进行预测。

但是,我很挣扎。我有一列(包含字符串值),例如:

Sex       
Male       
Female
# This is just as example, in real it is having much more unique values

现在问题来了。我收到了一个新的(唯一的)值,现在我无法再进行预测了(例如,添加了'Neutral')。

由于我将 'Sex' 列转换为 Dummies,我确实遇到了我的模型不再接受输入的问题,

模型的特征数量必须与输入相匹配。模型 n_features 为 2,输入 n_features 为 3

因此我的问题是:有没有办法让我的模型变得健壮,而忽略这个类?但是在没有具体信息的情况下进行预测?

我尝试过的:

df = pd.read_csv('dataset_that_i_want_to_predict.csv')
model = pickle.load(open("model_trained.sav", 'rb'))

# I have an 'example_df' containing just 1 row of training data (this is exactly what the model needs)
example_df = pd.read_csv('reading_one_row_of_trainings_data.csv')

# Checking for missing columns, and adding that to the new dataset 
missing_cols = set(example_df.columns) - set(df.columns)
for column in missing_cols:
    df[column] = 0 #adding the missing columns, with 0 values (Which is ok. since everything is dummy)

# make sure that we have the same order 
df = df[example_df.columns] 

# The prediction will lead to an error!
results = model.predict(df)

# ValueError: Number of features of the model must match the input. Model n_features is X and n_features is Y

注意,我搜索过,但找不到任何有用的解决方案(不是 here、here 或 here

更新

还发现this 文章。但同样的问题......我们可以让测试集与训练集具有相同的列......但是新的现实世界数据呢(例如新值“中性”)?

【问题讨论】:

如果过滤掉(删除)带有“中性”的条目,其他条目是否会生成没有错误的预测? 嗨,瑞克,是的。由于该列已转换为虚拟列,因此我们有一个名为“Sex_Male”、Sex_Female 的列。看起来模型正在接受一行,其中两个值都是 0。 一个快速解决方法(不是真的推荐)是在您的训练数据中创建另一个类作为“其他”,并可能使用您的数据集为其他特征生成一些人工数据。并且,在“性别”特征中获得“男性”或“女性”以外的任何内容后,您可以将其预处理为“其他”,并提供给模型。然而,这不是一个好方法,因为它无法捕捉到足够广泛的预期事物,并且可能会以不好的方式影响模型性能。更简单、更可靠的方法是固定那些名义上的特征,不接受“其他”,考虑“性别”。 【参考方案1】:

是的,在训练部分完成后,您不能在数据集中包含(更新模型)新类别或特征。 OneHotEncoder 可能会处理在测试数据的某些特征中包含新类别的问题。 它将负责在分类变量方面保持训练和测试数据中的列一致。

from sklearn.compose import ColumnTransformer
from sklearn.pipeline import Pipeline
from sklearn.linear_model import LogisticRegression
from sklearn.preprocessing import OneHotEncoder
import numpy as np
import pandas as pd
from sklearn import set_config
set_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)

# let us introduce new categories in feature_2 in test data
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)

【讨论】:

感谢@Venkatachalam,是否可以解释一下“管道”功能的作用,尤其是结合“预处理”、“ohe”和 OneHotEncoder 的作用?我可以假设它创建了一个管道,自动将新数据转换为虚拟数据,如果一个值是新的,它会忽略它吗?所以,我的真实数据包含数值和类别。我可以假设这个函数也将替换整个 pd_getdummies() 函数(我用于预处理数据吗?)再次感谢! pipeline 只是一个方便的对象,用于在拟合最终模型之前将我们想要在数据集上应用的所有步骤序列放置。请阅读here 和here 以获得更多解释。是的,你可以假设这个函数将替换整个pd.get_dummies() 更新:您需要提供remainder='passthrough' 以允许将其他列添加到 columnTransformer 的输出。\

以上是关于我们能否通过接受(或忽略)新特性使 ML 模型(pickle 文件)更加健壮?的主要内容,如果未能解决你的问题,请参考以下文章

您能否从头开始训练具有特定任务架构的BERT模型?

SVM(或其他 ML 模型)的预测准确度取决于特征的编码方式?

如果表单本身从未持久化,您能否使表单对象适用于新操作和编辑操作?

Day1 机器学习(Machine Learning, ML)基础

Oracle 11g 新特性 -- Invisible Indexes(不可见的索引) 说明

在本地使用 AWS ML 模型 Random Cut Forest