为何GridSearchCV单折交叉验证的ROC分数与score/roc_auc_score结果不符?
GridSearchCV单折交叉验证分数与后续计算结果不一致
问题现象
在测试sklearn的GridSearchCV时,发现用自定义可迭代对象定义单折交叉验证后,cv_results_中的平均ROC分数,和拟合后调用score方法或roc_auc_score函数计算的结果完全不同。
数据情况
print(X.shape) print(X.index) print(y.shape) print(y.index)
输出:
(31695, 1379) RangeIndex(start=0, stop=31695, step=1) (31695,) RangeIndex(start=0, stop=31695, step=1)
自定义交叉验证拆分
cv_split =[(np.arange(15848), np.arange(15848,31695))] cv_split
输出:
[(array([ 0, 1, 2, ..., 15845, 15846, 15847]), array([15848, 15849, 15850, ..., 31692, 31693, 31694]))]
GridSearchCV拟合结果
gs_algorithm = GridSearchCV(estimator=LGBMClassifier(), param_grid=hyperparameter_space, scoring='roc_auc', n_jobs=1, pre_dispatch=1, cv=cv_split, verbose=10, return_train_score=True) gs_algorithm.fit(X, y) gs_algorithm.cv_results_
输出中关键部分:
'split0_test_score': array([0.75898716]), 'mean_test_score': array([0.75898716]), 'split0_train_score': array([0.81224109]), 'mean_train_score': array([0.81224109])
后续计算结果
调用score方法:
gs_algorithm.score(X.iloc[cv_split[0][1]],y[cv_split[0][1]])
输出:
0.8194048788870386
用roc_auc_score计算:
y_pred = gs_algorithm.predict_proba(X)[:, 1] print(y_pred[cv_split[0][1]].shape) roc_auc_score(y[cv_split[0][1]], y_pred[cv_split[0][1]])
输出:
(15847,) 0.8194048788870386
核心原因
这是GridSearchCV的默认refit=True参数导致的:
- 交叉验证过程中,
cv_results_里的split0_test_score是用**单折训练集(前15848个样本)**训练的模型,在对应测试集(后15847个样本)上计算的得分。 - 交叉验证完成后,GridSearchCV会自动用全部X和y数据重新训练一个使用最佳参数的模型,这个模型才是你后续调用
score、predict_proba时使用的模型。 - 全量数据训练的模型拟合能力更强,在测试集上的表现自然优于仅用一半数据训练的模型,所以得分更高。
验证与解决
如果想让后续计算的分数和交叉验证过程中的一致,可以设置refit=False,这样GridSearchCV不会用全量数据重新训练模型:
gs_algorithm = GridSearchCV(estimator=LGBMClassifier(), param_grid=hyperparameter_space, scoring='roc_auc', n_jobs=1, pre_dispatch=1, cv=cv_split, verbose=10, return_train_score=True, refit=False) # 关闭自动重新训练 gs_algorithm.fit(X, y) # 此时用交叉验证中训练的模型计算测试集得分 from sklearn.metrics import roc_auc_score model = gs_algorithm.best_estimator_ y_pred = model.predict_proba(X.iloc[cv_split[0][1]])[:,1] print(roc_auc_score(y[cv_split[0][1]], y_pred)) # 结果会等于0.75898716
总结
cv_results_中的分数是交叉验证阶段,用单折训练数据训练的模型在对应测试集上的表现。- 默认
refit=True时,最终得到的是用全量数据重新训练的模型,后续所有调用都是基于这个模型。 - 若需复用交叉验证中的模型,设置
refit=False即可。
内容的提问来源于stack exchange,提问作者pepegalleta
相关产品推荐
相关产品推荐

