Sklearn将fit()参数传递到xgboost管道中

16

类似于如何在scikit learn中仅向管道对象的一个部分传递参数?我想要仅向管道的某个部分传递参数。通常,它应该像这样正常工作:

estimator = XGBClassifier()
pipeline = Pipeline([
        ('clf', estimator)
    ])

并像执行一样

pipeline.fit(X_train, y_train, clf__early_stopping_rounds=20)

但它失败了:

    /usr/local/lib/python3.5/site-packages/sklearn/pipeline.py in fit(self, X, y, **fit_params)
        114         """
        115         Xt, yt, fit_params = self._pre_transform(X, y, **fit_params)
    --> 116         self.steps[-1][-1].fit(Xt, yt, **fit_params)
        117         return self
        118 

    /usr/local/lib/python3.5/site-packages/xgboost-0.6-py3.5.egg/xgboost/sklearn.py in fit(self, X, y, sample_weight, eval_set, eval_metric, early_stopping_rounds, verbose)
        443                               early_stopping_rounds=early_stopping_rounds,
        444                               evals_result=evals_result, obj=obj, feval=feval,
    --> 445                               verbose_eval=verbose)
        446 
        447         self.objective = xgb_options["objective"]

    /usr/local/lib/python3.5/site-packages/xgboost-0.6-py3.5.egg/xgboost/training.py in train(params, dtrain, num_boost_round, evals, obj, feval, maximize, early_stopping_rounds, evals_result, verbose_eval, learning_rates, xgb_model, callbacks)
        201                            evals=evals,
        202                            obj=obj, feval=feval,
    --> 203                            xgb_model=xgb_model, callbacks=callbacks)
        204 
        205 

    /usr/local/lib/python3.5/site-packages/xgboost-0.6-py3.5.egg/xgboost/training.py in _train_internal(params, dtrain, num_boost_round, evals, obj, feval, xgb_model, callbacks)
         97                                end_iteration=num_boost_round,
         98                                rank=rank,
    ---> 99                                evaluation_result_list=evaluation_result_list))
        100         except EarlyStopException:
        101             break

    /usr/local/lib/python3.5/site-packages/xgboost-0.6-py3.5.egg/xgboost/callback.py in callback(env)
        196     def callback(env):
        197         """internal function"""
    --> 198         score = env.evaluation_result_list[-1][1]
        199         if len(state) == 0:
        200             init(env)

    IndexError: list index out of range

然而,一个

estimator.fit(X_train, y_train, early_stopping_rounds=20)

运行得很好。

4个回答

17

在进行早停轮次时,您必须始终指定由eval_set参数给出的验证集。以下是如何修复代码中的错误。

pipeline.fit(X_train, y_train, clf__early_stopping_rounds=20, clf__eval_set=[(test_X, test_y)])

想知道在管道中包含StandardScaler或者列删除时的最佳实践是什么。在当前情况下,test_X不需要进行必要的更改。哦,下面已经回答了这个问题。 - Anatoly Alekseev

14

我最近使用了以下步骤来使用Xgboost的eval metric和eval_set参数。

1. 创建包含预处理/特征转换步骤的流水线:

这是由先前定义的包含xgboost模型作为最后一步的管道创建的。

pipeline_temp = pipeline.Pipeline(pipeline.cost_pipe.steps[:-1])  

2. 适用于此管道

X_trans = pipeline_temp.fit_transform(X_train[FEATURES],y_train)

3. 将变换应用于测试集以创建您的eval_set

eval_set = [(X_trans, y_train), (pipeline_temp.transform(X_test), y_test)]

4.将xgboost步骤重新添加到管道中

 pipeline_temp.steps.append(pipeline.cost_pipe.steps[-1])

5. 通过传递参数来调整新的管道

pipeline_temp.fit(X_train[FEATURES], y_train,
             xgboost_model__eval_metric = ERROR_METRIC,
             xgboost_model__eval_set = eval_set)

6. 如果您希望保留管道,请进行持久化。

joblib.dump(pipeline_temp, save_path)

3
这似乎是所有发布的答案中最佳的解决方案。 - Harshith Thota
这在scikit-learn的0.23.2版本中无法工作。 - ucsky
嘿@ucsky,你能建议一下上面的代码哪个具体部分不起作用吗? - gdv820
很好的回答,但是在第5步中的第二个fit()调用似乎会重复第2步的所有计算。有没有办法保存它们?也许我们可以用fit_transform替换第2步,并将输出保存为X_train_processed和Y_train_processed,在第5步中使用它们来代替原始的X和y? - Anatoly Alekseev

8

8
我认为如果你取消对这个答案的采纳会更好。你的问题基本上是“如何在sklearn管道中做[x]”,而你链接的答案并没有使用sklearn管道。你甚至在你接受的答案中说,“由于这个原因,这种方法对我不起作用”。如果有人提供了在管道中如何执行此操作的答案,那么最好接受该答案。 - Max Power

0

以下是适用于Pipeline和GridSearchCV的解决方案:

覆盖XGBRegressor或XGBClssifier.fit()函数

  • 此步骤使用train_test_split()从X中选择指定数量的验证记录作为eval_set,然后将其余记录传递给fit()。
  • 添加了一个新参数eval_test_size到.fit()中,以控制验证记录的数量。(请参阅train_test_split test_size文档)
  • **kwargs会传递用户添加的任何其他参数到XGBRegressor.fit()函数中。
from xgboost.sklearn import XGBRegressor
from sklearn.model_selection import train_test_split

class XGBRegressor_ES(XGBRegressor):
    
    def fit(self, X, y, *, eval_test_size=None, **kwargs):
        
        if eval_test_size is not None:
        
            params = super(XGBRegressor, self).get_xgb_params()
            
            X_train, X_test, y_train, y_test = train_test_split(
                X, y, test_size=eval_test_size, random_state=params['random_state'])
            
            eval_set = [(X_test, y_test)]
            
            # Could add (X_train, y_train) to eval_set 
            # to get .eval_results() for both train and test
            #eval_set = [(X_train, y_train),(X_test, y_test)] 
            
            kwargs['eval_set'] = eval_set
            
        return super(XGBRegressor_ES, self).fit(X_train, y_train, **kwargs) 

示例用法

下面是一个多步骤的管道,其中包括对 X 进行多次转换。管道的 fit() 函数将新的评估参数传递给上面的 XGBRegressor_ES 类,如 xgbr__eval_test_size=200。在这个例子中:

  • X_train 包含传递到管道中的文本文档。
  • XGBRegressor_ES.fit() 使用 train_test_split() 从 X_train 中选择 200 条记录作为验证集和早期停止。(这也可以是一个百分比,例如 xgbr__eval_test_size=0.2)
  • X_train 中剩余的记录被传递给 XGBRegressor.fit() 进行实际的拟合。
  • 在网格搜索的每个 cv 折叠中,经过 75 轮未改变的增强后,现在可以进行早期停止。
from sklearn.pipeline import Pipeline
from sklearn.feature_extraction.text import TfidfVectorizer
from sklearn.feature_selection import VarianceThreshold
from sklearn.preprocessing import StandardScaler
from sklearn.feature_selection import SelectPercentile, f_regression
   
xgbr_pipe = Pipeline(steps=[('tfidf', TfidfVectorizer()),
                     ('vt',VarianceThreshold()),
                     ('scaler', StandardScaler()),
                     ('Sp', SelectPercentile()),
                     ('xgbr',XGBRegressor_ES(n_estimators=2000,
                                             objective='reg:squarederror',
                                             eval_metric='mae',
                                             learning_rate=0.0001,
                                             random_state=7))    ])

X_train = train_idxs['f_text'].values
y_train = train_idxs['Pct_Change_20'].values

示例拟合管道:

%time xgbr_pipe.fit(X_train, y_train, 
                    xgbr__eval_test_size=200,
                    xgbr__eval_metric='mae', 
                    xgbr__early_stopping_rounds=75)

示例拟合GridSearchCV:

learning_rate = [0.0001, 0.001, 0.01, 0.05, 0.1, 0.2, 0.3]
param_grid = dict(xgbr__learning_rate=learning_rate)

grid_search = GridSearchCV(xgbr_pipe, param_grid, scoring="neg_mean_absolute_error", n_jobs=-1, cv=10)
grid_result = grid_search.fit(X_train, y_train, 
                    xgbr__eval_test_size=200,
                    xgbr__eval_metric='mae', 
                    xgbr__early_stopping_rounds=75)

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接