【问题标题】:Pipeline with XGBoost - Imputer and Scaler prevent Model from learning使用 XGBoost 的管道 - Imputer 和 Scaler 阻止模型学习
【发布时间】:2023-01-13 01:02:32
【问题描述】:

我正在尝试为我的 XGBoost 模型构建数据预处理管道。数据包含 NaN,需要缩放。这是相关代码:

xgb_pipe = Pipeline(steps=[
    ('imputer', SimpleImputer(strategy='mean')),
    ('scaler', preprocessing.StandardScaler()),
    ('regressor', xgboost.XGBRegressor(n_estimators=100, eta=0.1, objective = "reg:squarederror"))])

xgb_pipe.fit(train_x.values, train_y.values, 
            regressor__early_stopping_rounds=20, 
            regressor__eval_metric = "rmse", 
            regressor__eval_set = [[train_x.values, train_y.values],[test_x.values, test_y.values]])

损失立即增加,训练在 20 次迭代后停止。

如果我从管道中删除输入器和缩放器,它会工作并训练完整的 100 次迭代。如果我手动预处理数据,它也会按预期工作,所以我知道问题不在于数据。 我错过了什么?

【问题讨论】:

  • 必须与您的 regressor__eval_set fit 参数相关。对于初学者,将其排除在外,并查看 XGBoost 是否运行了 100 次迭代。
  • @user1808924 如果我只删除这一行,我会得到一个IndexError:列表索引超出范围错误。如果我删除所有三个回归变量参数以提前停止,它会在整个持续时间内进行训练(并且损失会按预期改善)。那么实施提前停止的正确方法是什么?
  • 请注意,(梯度提升)树不关心输入的规模,因此这里并不严格需要 StandardScaler。而 xgboost 将处理缺失值(但如果你想要那个,那么估算将导致差异。)

标签: scikit-learn data-science pipeline xgboost data-preprocessing


【解决方案1】:

问题是预处理没有应用于您的评估集,因此模型在它们上的表现非常糟糕,并且提前停止很早就开始了。

不幸的是,我不确定是否有一种简单的方法可以将所有内容都保存在一个管道中。您需要将管道的预处理步骤应用于评估集,因此需要在设置该参数之前安装这些步骤。

单独预处理

作为两个对象没问题:

preproc = Pipeline(steps=[
    ('imputer', SimpleImputer(strategy='mean')),
    ('scaler', preprocessing.StandardScaler()),
])

reg = xgboost.XGBRegressor(n_estimators=100, eta=0.1, objective="reg:squarederror")

train_x_preproc = preproc.fit_transform(train_x.values, train_y.values)
test_x_preproc = preproc.transform(test_x)

reg.fit(train_x.values, train_y.values, 
    regressor__early_stopping_rounds=20, 
    regressor__eval_metric = "rmse", 
    regressor__eval_set = [[train_x_preproc, train_y.values], [test_x_preproc, test_y.values]],
)

拟合后,如果您愿意,您可以将这些现在拟合的估计器一起放入管道(管道不会克隆它们的估计器)进行预测。

自定义估算器

有很多方法可以解决这个问题,但是从Pipeline 继承意味着您可以按照与当前设置相同的方式进行初始化,我们只是假设最后一步是 xgboost 模型,其余的是预处理,需要适用于评估集以及拟合和预测集。我认为其他一切都可以留给Pipeline的继承方法?

class PreprocEarlyStoppingXGB(Pipeline):
    def fit(self, X, y, eval_set):
        preproc = self.steps[:-1]
        X_preproc = preproc.fit_transform(X, y)
        eval_preproc = []
        for eval in eval_set:
            eval_preproc.append([preproc.transform(eval[0]), eval[1]])
        self.steps[-1].fit(X_preproc, y, eval_set=eval_preproc)
        return self

对于来自 cmets 的用例,当您使用此对象进行交叉验证时会发生什么?在每个训练折叠上,都安装了预处理步骤。然后将它们应用于训练折叠和所有评估集(整个训练集以及外部测试集),最后在对测试折叠进行评分时。 xgboost 模型在预处理后的训练集上进行训练,并观察整个训练集和外部测试集(均已预处理)的得分,后者用于提前停止。

【讨论】:

  • 这就说得通了。这将如何与 kfold 交叉验证相结合?我实施了管道以进行简单的网格搜索/kfold 评估,其中分别为 5 个训练/评估拆分中的每一个分别安装缩放/输入,以避免数据泄漏。下一步应该是这样的:CV = GridSearchCV(xgb_pipe, param_grid)
  • @Jonas 是的,这是不将所有内容都放在一个对象中的主要缺点。我添加了一个我认为应该完成这项工作的自定义估算器;也许没有它也可以做些什么,但我看不到。
猜你喜欢
  • 2013-07-28
  • 1970-01-01
  • 2022-06-14
  • 1970-01-01
  • 2016-07-28
  • 2021-10-12
  • 1970-01-01
  • 2016-06-21
  • 1970-01-01
相关资源
最近更新 更多