scikit-optimize 中 cv_results_ 和 best_score_ 中的测试分数是如何计算的?

问题描述

我正在使用 BayesSearchCV 中的 scikit-optimize 来优化 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,'subsample': Real(0.25,1.0,'learning_rate': Real(0.0001,0.5,'gamma': Real(0.0001,'colsample_bytree': Real(0.0001,'colsample_bylevel': Real(0.0001,'colsample_bynode': Real(0.0001,'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...不知道为什么这里有精度差异。)

解决方法

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


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

相关问答

Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其...
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。...
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbc...