【问题标题】:GridSearchCV not choosing the best hyperparameters for xgboostGridSearchCV 没有为 xgboost 选择最佳超参数
【发布时间】:2021-11-24 12:10:32
【问题描述】:

我目前正在使用 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 可以返回更好的 RSME 或 R^ 分数2 比max_depth:2。谁能告诉我为什么当我将max_depth 设置为[2,3] 时我的代码无法选择最佳超参数?

【问题讨论】:

  • 网格搜索根据其内部交叉验证分数选择最佳超参数(查看其属性cv_results_);不能保证获胜者在新的测试集上表现最好。

标签: python machine-learning scikit-learn xgboost


【解决方案1】:

如果您使用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?

中的回答

【讨论】:

  • 谢谢!你是说如果我用max_depth:[2,3]运行GridSearchCVmax_depth:3的结果会受到max_depth:2之前结果的影响,所以最好的超参数会变成max_depth:2,对吗?如果是,我想让每个结果都相同。在这种情况下,我应该像你在另一个线程中解释的那样运行for 循环并执行我的手动GridSearch 吗?
  • @shumach5 我没有说最好的超参数;我只是说结果与使用 max_depth:3 运行单次运行不同,我解释了原因。不幸的是,并不是所有的实验都可以在这个意义上完全具有可比性,正如我也提到的 - 随机性从太多的角度进入
  • 感谢您的回答!所以我错过的关键因素是结果不一样。
猜你喜欢
  • 2020-10-10
  • 1970-01-01
  • 1970-01-01
  • 2019-07-25
  • 2020-12-01
  • 2017-05-19
  • 2017-04-11
  • 2017-05-31
  • 2021-08-22
相关资源
最近更新 更多