GridSearchCV 没有为 xgboost 选择最佳超参数

shu*_*ch5 3 python machine-learning scikit-learn xgboost

我目前正在使用 xgboost 开发回归模型。由于 xgboost 有多个超参数,因此我添加了与GridSearchCV(). 作为试验,我设置了max_depth: [2,3]. 我的Python代码如下。

\n
from sklearn.model_selection import GridSearchCV\nfrom sklearn.metrics import make_scorer\nfrom sklearn.metrics import mean_squared_error\n\xe2\x80\x8b\nxgb_reg = xgb.XGBRegressor()\n\xe2\x80\x8b\n# Obtain the best hyper parameter\nscorer=make_scorer(mean_squared_error, False)\nparams = {'max_depth': [2,3], \n          'eta': [0.1], \n          'colsample_bytree': [1.0],\n          'colsample_bylevel': [0.3],\n          'subsample': [0.9],\n          'gamma': [0],\n          'lambda': [1],\n          'alpha':[0],\n          'min_child_weight':[1]\n         }\ngrid_xgb_reg=GridSearchCV(xgb_reg,\n                          param_grid=params,\n                          scoring=scorer,\n                          cv=5,\n                          n_jobs=-1)\n\xe2\x80\x8b\ngrid_xgb_reg.fit(X_train, y_train)\ny_pred = grid_xgb_reg.predict(X_test)\ny_train_pred = grid_xgb_reg.predict(X_train)\n\n## Evaluate model\nfrom sklearn.metrics import mean_squared_error\nfrom sklearn.metrics import r2_score\n\xe2\x80\x8b\nprint('RMSE  train: %.3f,  test: %.3f' %(np.sqrt(mean_squared_error(y_train, y_train_pred)),np.sqrt(mean_squared_error(y_test, y_pred))))\nprint('R^2   train: %.3f,  test: %.3f' %(r2_score(y_train, y_train_pred),r2_score(y_test, y_pred)))\n
Run Code Online (Sandbox Code Playgroud)\n

问题是GridSearchCV似乎没有选择最好的超参数。就我而言,当我设置max_depth为时[2,3],结果如下。在以下情况下,GridSearchCV选择max_depth:2最佳超参数。

\n
#  The result when max_depth is 2\nRMSE  train: 11.861,  test: 15.113\nR^2   train: 0.817,  test: 0.601\n
Run Code Online (Sandbox Code Playgroud)\n

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

\n
#  The result when max_depth is 3\nRMSE  train: 9.951,  test: 14.752\nR^2   train: 0.871,  test: 0.620\n
Run Code Online (Sandbox Code Playgroud)\n

问题

\n

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

\n

des*_*aut 5

如果您使用 运行第二个实验,那么即使使用 运行,max_depth:2结果也无法与第一个实验相比较,因为您的代码中存在您没有明确控制的随机性来源,即您的代码不可重现max_depth:[2,3]max_depth:2

随机性的第一个来源是 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)
Run Code Online (Sandbox Code Playgroud)

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

seed_xgb = 456 # any random value here (can even be the same with seed_cv)
xgb_reg = xgb.XGBRegressor(random_state=seed_xgb)
Run Code Online (Sandbox Code Playgroud)

但即使采用这些安排,虽然您的数据分割现在将是相同的,但构建的回归模型在一般情况下不一定如此;在这里,如果你保持这样的实验,即先用 max_depth:[2,3],然后用max_depth:2,结果确实是相同的;但如果你将其更改为,例如,先 with max_depth:[2,3],然后 with max_depth:3,则它们不会因为在第一个实验中,运行 withmax_depth:3将以随机数生成器的不同状态开始(即运行max_depth:2完成后的状态) 。

在这种条件下,不同运行的相同程度是有限的;有关一个非常微妙的差异的示例,该差异仍然破坏了两个实验之间的精确再现性,请参阅我的回答:为什么重要性参数会影响 R 中随机森林的性能?