在 SciKit-Learn 中使用 XGBoost 交叉验证进行网格搜索和提前停止
Posted
技术标签:
【中文标题】在 SciKit-Learn 中使用 XGBoost 交叉验证进行网格搜索和提前停止【英文标题】:Grid Search and Early Stopping Using Cross Validation with XGBoost in SciKit-Learn 【发布时间】:2017-10-07 13:20:56 【问题描述】:我对 sci-kit learn 还很陌生,并且一直在尝试对 XGBoost 进行超参数调整。我的目标是使用提前停止和网格搜索来调整模型参数,并使用提前停止来控制树的数量并避免过度拟合。
由于我对网格搜索使用交叉验证,我希望在早期停止条件中也使用交叉验证。到目前为止,我的代码如下所示:
import numpy as np
import pandas as pd
from sklearn import model_selection
import xgboost as xgb
#Import training and test data
train = pd.read_csv("train.csv").fillna(value=-999.0)
test = pd.read_csv("test.csv").fillna(value=-999.0)
# Encode variables
y_train = train.price_doc
x_train = train.drop(["id", "timestamp", "price_doc"], axis=1)
# XGBoost - sklearn method
gbm = xgb.XGBRegressor()
xgb_params =
'learning_rate': [0.01, 0.1],
'n_estimators': [2000],
'max_depth': [3, 5, 7, 9],
'gamma': [0, 1],
'subsample': [0.7, 1],
'colsample_bytree': [0.7, 1]
fit_params =
'early_stopping_rounds': 30,
'eval_metric': 'mae',
'eval_set': [[x_train,y_train]]
grid = model_selection.GridSearchCV(gbm, xgb_params, cv=5,
fit_params=fit_params)
grid.fit(x_train,y_train)
我遇到的问题是“eval_set”参数。我知道这需要预测变量和响应变量,但我不确定如何使用交叉验证数据作为提前停止标准。
有谁知道如何解决这个问题?谢谢。
【问题讨论】:
【参考方案1】:在 GridSearchCV 中包含提前停止没有多大意义。提前停止用于快速找到训练/有效情况下的最佳 n_rounds。如果我们不关心“快速”,我们可以调整 n_rounds。假设 GridSearchCV 具有为每个折叠执行提前停止 n_rounds 的功能,那么对于每组超参数,我们将有 N(折叠数) n_rounds。也许 n_rounds 的平均值可以用于最终的最佳超参数集,但当 n_rounds 彼此相差太大时,它可能不是一个好的选择。因此,在 GridSearchCV 中包含提前停止可能会提高 Trianing 的速度,但结果可能不是最好的。
接受的答案中建议的方法更像是调整 n_rounds 参数而不是提前停止,因为作者承认“它不会节省评估所有可能的 n_rounds 所需的计算时间”。
【讨论】:
【参考方案2】:使用xgboost
原创。
从数据Dmatrix
生成并使用xgboost.cv
tutorial
【讨论】:
【参考方案3】:您可以将 early_stopping_rounds 和 eval_set 作为额外的 fit_params 传递给 GridSearchCV,这实际上是可行的。但是,GridSearchCV 不会更改不同折叠之间的 fit_params,因此您最终会在所有折叠中使用相同的 eval_set,这可能不是您所说的 CV。
model=xgb.XGBClassifier()
clf = GridSearchCV(model, parameters,
fit_params='early_stopping_rounds':20,\
'eval_set':[(X,y)],cv=kfold)
经过一些调整,我发现整合 early_stopping_rounds 和sklearn
API 最安全的方法是自己实现 early_stopping 机制。如果您使用 n_rounds 作为要调整的参数执行GridSearchCV
,则可以这样做。然后,您可以随着n_rounds
的增加观察不同模型的 mean_validation_score。然后,您可以为提前停止定义自定义启发式。它不会节省评估所有可能的n_rounds
所需的计算时间
我认为这也是一种更好的方法,然后为此目的使用单个拆分保持。
【讨论】:
@Martijn Pieters 当这个被接受时,我会将另一个标记为重复。我不能,因为这还没有回答 @00_00_00 你能具体说明'eval_set':[(X,y)]
是做什么的吗?我认为当我们 clf.fit(X_total,y_total) 时,数据X_total
将分为训练集和测试集。如果我们将ealy_stopping_rounds
设置为fit_params
,则模型将在训练集上进行训练并在测试集上进行评估。因此,我们不需要为 early_stopping 传递额外的'eval_set':[(X,y)]
。我说得通吗?
如果我们不将 'eval_set':[(X,y)] 传递给fit_params
,代码将引发类似this 的错误。似乎我们做了一个网格搜索,将 X_total 分成 n 次折叠,并将模型从折叠 n 次中拟合出来,每次都使用 eval_set':[(X,y)] 拟合模型早期停止。所以我认为它不符合 CV 的想法,这意味着建立模型并在每个折叠上进行评估。
@Travis,我不太明白你的意思。提前停止总是根据为所有 cv 折叠提供的 (X,y) 完成。只要在保留数据集上计算准确度指标,我们最终将获得正确的“平均测试”分数,从而获得最佳 XGB。我不明白这里有什么不一致的地方。你能解释一下吗?以上是关于在 SciKit-Learn 中使用 XGBoost 交叉验证进行网格搜索和提前停止的主要内容,如果未能解决你的问题,请参考以下文章
scikit-learn:在管道中使用 SelectKBest 时获取选定的功能
如何在 scikit-learn(用于计算机视觉)中使用我自己的数据集?
在 scikit-learn 库中使用 sgd 求解器的 SGDClassifier 与 LogisticRegression