### GridSearchCV未能为xgboost选择最佳超参数

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

from sklearn.model_selection import GridSearchCVfrom sklearn.metrics import make_scorerfrom sklearn.metrics import mean_squared_error

xgb_reg = xgb.XGBRegressor()

# 获得最佳超参数
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)
## 评估模型
from sklearn.metrics import mean_squared_errorfrom 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作为最佳超参数。

# 当max_depth为2时的结果
RMSE  train: 11.861,  test: 15.113
R^2   train: 0.817,  test: 0.601

然而,如果我将max_depth更新为[3](去掉2),测试分数比之前的值更好,如下所示。

# 当max_depth为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]时,我的代码无法选择最佳超参数?


回答:

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

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

from sklearn.model_selection import KFold
seed_cv = 123 # 这里可以是任何随机值
kf = KFold(n_splits=5, random_state=seed_cv)
grid_xgb_reg=GridSearchCV(xgb_reg,
                          param_grid=params,
                          scoring=scorer,
                          cv=kf,   # <- 在这里更改
                          n_jobs=-1)

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

seed_xgb = 456 # 这里可以是任何随机值(甚至可以与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运行结束后的状态)。

在这种情况下,不同运行的可重现性是有限的;关于一个非常微妙的差异如何破坏两个实验之间的精确可重现性的例子,请参见我在为什么重要性参数会影响R中随机森林的性能?中的回答

Related Posts

使用LSTM在Python中预测未来值

这段代码可以预测指定股票的当前日期之前的值,但不能预测…

如何在gensim的word2vec模型中查找双词组的相似性

我有一个word2vec模型,假设我使用的是googl…

dask_xgboost.predict 可以工作但无法显示 – 数据必须是一维的

我试图使用 XGBoost 创建模型。 看起来我成功地…

ML Tuning – Cross Validation in Spark

我在https://spark.apache.org/…

如何在React JS中使用fetch从REST API获取预测

我正在开发一个应用程序,其中Flask REST AP…

如何分析ML.NET中多类分类预测得分数组?

我在ML.NET中创建了一个多类分类项目。该项目可以对…

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注