GridSearchCV没有为xgBoost选择最佳的超参数

人气:82 发布:2023-01-03 标签: python scikit-learn machine-learning xgboost

问题描述

我目前正在使用XgBoost开发一个回归模型。因为xgBoost有多个超参数,所以我用GridSearchCV()添加了交叉验证逻辑。作为试验,我设置了max_depth: [2,3]。我的python代码如下所示。

from sklearn.model_selection import GridSearchCV
from sklearn.metrics import make_scorer
from sklearn.metrics import mean_squared_error
​
xgb_reg = xgb.XGBRegressor()
​
# Obtain the best hyper parameter
scorer=make_scorer(mean_squared_error, False)
params = {'max_depth': [2,3], 
          'eta': [0.1], 
          'colsample_bytree': [1.0],
          'colsample_bylevel': [0.3],
          'subsample': [0.9],
          'gamma': [0],
          'lambda': [1],
          'alpha':[0],
          'min_child_weight':[1]
         }
grid_xgb_reg=GridSearchCV(xgb_reg,
                          param_grid=params,
                          scoring=scorer,
                          cv=5,
                          n_jobs=-1)
​
grid_xgb_reg.fit(X_train, y_train)
y_pred = grid_xgb_reg.predict(X_test)
y_train_pred = grid_xgb_reg.predict(X_train)

## Evaluate model
from sklearn.metrics import mean_squared_error
from sklearn.metrics import r2_score
​
print('RMSE  train: %.3f,  test: %.3f' %(np.sqrt(mean_squared_error(y_train, y_train_pred)),np.sqrt(mean_squared_error(y_test, y_pred))))
print('R^2   train: %.3f,  test: %.3f' %(r2_score(y_train, y_train_pred),r2_score(y_test, y_pred)))

问题是GridSearchCV似乎没有选择最佳的超参数。在我的例子中,当我将max_depth设置为[2,3]时,结果如下所示。在以下情况下,GridSearchCV选择max_depth:2作为最佳超级参数。

#  The result when max_depth is 2
RMSE  train: 11.861,  test: 15.113
R^2   train: 0.817,  test: 0.601

但是,如果我将max_depth更新为[3](通过删除2),测试分数将比以前的值更好,如下所示。

#  The result when max_depth is 3
RMSE  train: 9.951,  test: 14.752
R^2   train: 0.871,  test: 0.620

问题

我的理解是,即使我将max_depth设置为[2,3]GridSearchCV方法也应该选择max_depth:3作为最佳超参数,因为max_depth:3可以返回比max_depth:2更好的RSME或R^2分数。谁能告诉我,当我将max_depth设置为[2,3]时,为什么我的代码无法选择最佳的超参数?

推荐答案

如果您使用max_depth:2运行第二次实验,则即使使用max_depth:2运行,结果也无法与使用max_depth:[2,3]进行的第一次实验相比,因为您的代码中存在未显式控制的随机性来源,即您的代码不能重现。

第一个随机性来源是CV折叠;为了确保实验将在相同的数据拆分上运行,您应该按如下方式定义GridSearchCV:

from sklearn.model_selection import KFold

seed_cv = 123 # any random value here

kf = KFold(n_splits=5, random_state=seed_cv)

grid_xgb_reg=GridSearchCV(xgb_reg,
                          param_grid=params,
                          scoring=scorer,
                          cv=kf,   # <- change here
                          n_jobs=-1)

第二个随机性来源是XGBRegressor本身,它还包含random_state参数(请参阅docs);您应该将其更改为:

seed_xgb = 456 # any random value here (can even be the same with seed_cv)
xgb_reg = xgb.XGBRegressor(random_state=seed_xgb)
但是,即使有了这些安排,虽然现在您的数据拆分将是相同的,但建立的回归模型在一般情况下不一定是这样的;在这里,如果您保持这样的实验,即首先使用max_depth:[2,3],然后使用max_depth:2,结果将确实相同;但是,如果您先将其更改为max_depth:[2,3],然后更改为max_depth:3,则不会,因为在第一个实验中,max_depth:3的运行将以随机数生成器的不同状态开始(即,max_depth:2运行后的状态已经结束)。

在这种情况下进行不同运行的相同程度是有限制的;有关非常细微的差异的示例,但它会破坏两个实验之间的精确重复性,请参阅Why does the importance parameter influence performance of Random Forest in R?

中的我的答案

18