【问题标题】:How are the test scores in cv_results_ and best_score_ calculated in scikit-optimize?scikit-optimize 中的 cv_results_ 和 best_score_ 的测试分数是如何计算的?
【发布时间】:2021-06-20 08:59:21
【问题描述】:

我正在使用来自scikit-optimizeBayesSearchCV 来优化XGBoost 模型以适应我拥有的一些数据。虽然模型很合适,但我对诊断信息中提供的分数感到困惑,无法复制它们。

这是一个使用波士顿房价数据集的示例脚本来说明我的观点:

from sklearn.datasets import load_boston

import numpy as np
import pandas as pd

from xgboost.sklearn import XGBRegressor

from skopt import BayesSearchCV
from skopt.space import Real, Categorical, Integer
from sklearn.model_selection import KFold, train_test_split 

boston = load_boston()

# Dataset info:
print(boston.keys())
print(boston.data.shape)
print(boston.feature_names)
print(boston.DESCR)

# Put data into dataframe and label column headers:

data = pd.DataFrame(boston.data)
data.columns = boston.feature_names

# Add target variable to dataframe

data['PRICE'] = boston.target

# Split into X and y

X, y = data.iloc[:, :-1],data.iloc[:,-1]

# Split into training and validation datasets 

X_train, X_val, y_train, y_val = train_test_split(X, y, test_size=0.2, random_state=42, shuffle = True) 

# For cross-validation, split training data into 5 folds

xgb_kfold = KFold(n_splits = 5,random_state = 42)

# Run fit

xgb_params = {'n_estimators': Integer(10, 3000, 'uniform'),
               'max_depth': Integer(2, 100, 'uniform'),
               'subsample': Real(0.25, 1.0, 'uniform'),
               'learning_rate': Real(0.0001, 0.5, 'uniform'),
               'gamma': Real(0.0001, 1.0, 'uniform'),
               'colsample_bytree': Real(0.0001, 1.0, 'uniform'),
               'colsample_bylevel': Real(0.0001, 1.0, 'uniform'),
               'colsample_bynode': Real(0.0001, 1.0, 'uniform'),
               'min_child_weight': Real(1, 6, 'uniform')}

xgb_fit_params = {'early_stopping_rounds': 15, 'eval_metric': 'mae', 'eval_set': [[X_val, y_val]]}

xgb_pipe = XGBRegressor(random_state = 42,  objective='reg:squarederror', n_jobs = 10)

xgb_cv = BayesSearchCV(xgb_pipe, xgb_params, cv = xgb_kfold, n_iter = 5, n_jobs = 1, random_state = 42, verbose = 4, scoring = None, fit_params = xgb_fit_params)

xgb_cv.fit(X_train, y_train)

运行后,xgb_cv.best_score_ 为 0.816,xgb_cv.best_index_ 为 3。查看 xgb_cv.cv_results_,我想找到每个折叠的最佳分数:

print(xgb_cv.cv_results_['split0_test_score'][xgb_cv.best_index_], xgb_cv.cv_results_['split1_test_score'][xgb_cv.best_index_], xgb_cv.cv_results_['split2_test_score'][xgb_cv.best_index_], xgb_cv.cv_results_['split3_test_score'][xgb_cv.best_index_], xgb_cv.cv_results_['split4_test_score'][xgb_cv.best_index_])

这给出了:

0.8023562337946979,
 0.8337404778903412,
 0.861370681263761,
 0.8749312273014963,
 0.7058815015739375

我不确定这里计算的是什么,因为 scoring 在我的代码中设置为 None。 XGBoost 的文档没有多大帮助,但根据xgb_cv.best_estimator_.score?,它应该是预测值的 R2。无论如何,当我手动尝试计算拟合中使用的数据的每一折的分数时,我无法获得这些值:

# First, need to get the actual indices of the data from each fold:

kfold_indexes = {}
kfold_cnt = 0

for train_index, test_index in xgb_kfold.split(X_train):
    kfold_indexes[kfold_cnt] = {'train': train_index, 'test': test_index}
    kfold_cnt = kfold_cnt+1

# Next, calculate the score for each fold   
for p in range(5): print(xgb_cv.best_estimator_.score(X_train.iloc[kfold_indexes[p]['test']], y_train.iloc[kfold_indexes[p]['test']]))

这给了我以下信息:

0.9954929618573786
0.994844803666101
0.9963108152027245
0.9962274544089832
0.9931314653538819

BayesSearchCV 如何计算每个折叠的分数,为什么我不能使用 score 函数复制它们?对于这个问题,我将不胜感激。

(另外,手动计算这些分数的平均值给出:0.8156560...,而xgb_cv.best_score_ 给出:0.8159277...不知道为什么这里有精度差异。)

【问题讨论】:

  • 你的第一组分数是test倍分数,而第二组分数是train倍分数。
  • @ benreiniger我尝试使用测试指标,但我仍然没有得到右边值:for p in range(5): print(xgb_cv.best_estimator_.score(X_train.iloc[kfold_indexes[p]['test']], y_train.iloc[kfold_indexes[p]['test']]))给出:0.9954929618573786,0.994844803666101,0.9963108152027245,0.9962274544089832,0.9962274544089832,0.9931314653538819,0.9931314653538819,0.9931314653538819 Span>
  • @BenReiniger:我已经按照您的建议更改了预测分数。我的方法还有什么问题?

标签: python machine-learning regression xgboost scikit-optimize


【解决方案1】:

best_estimator_ 是重新拟合的估计器,在选择超参数后拟合在整个训练集上;因此,在训练集的任何部分对其进行评分都将是乐观的。要重现 cv_results_,您需要将估计器重新拟合到每个训练折叠和 score 相应的测试折叠。


除此之外,XGBoost random_state 似乎确实没有涵盖更多随机性。还有一个参数seed;为我产生一致结果的设置。 (这里有一些较旧的帖子 (example) 报告了类似的问题,即使设置了seed,但也许这些问题已经被新版本的 xgb 解决了。)

【讨论】:

  • 如果是这种情况,那么是否应该将X_train 传递给score 提供与best_score_ 相同的值?因为我试过这样做,但价值仍然明显不同。
  • 没有。 best_score_是最大的mean_test_score,是根据out-of-fold分数计算的;而xgb_cv.scorexgb_cv.best_estimator_.score的简写,是再训练模型的评分方式,所以“作弊”。
  • 使用与 best_estimator_ 相同的参数重新调整了新的 XGBoost 模型后,我现在得到了更接近的值(原始 CV 分数:0.80235623, 0.83374048, 0.86137068, 0.87493123, 0.7058815 我的仿真尝试:0.81142551, 0.82771065, 0.87877982, 0.88612015, 0.70819454)。但它们仍然不准确。为什么还会有区别?
  • 嗯。您已经在所有 xgboost、kfold 和 bayessearch 中设置了随机状态,所以应该没问题。我假设相同的数据集。我会尝试使用 sklearn 的 GBM 和随机搜索,以区分效果是由于 xgboost 还是 skopt。
  • 我开始测试自己,这似乎是一个 xgboost 问题。我已添加到答案中。
猜你喜欢
  • 2014-07-28
  • 2022-01-04
  • 2021-02-10
  • 2017-05-18
  • 2020-11-30
  • 2019-09-06
  • 2013-12-19
  • 2021-05-02
  • 2021-04-17
相关资源
最近更新 更多