You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

为何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参数导致的:

  1. 交叉验证过程中,cv_results_里的split0_test_score是用**单折训练集(前15848个样本)**训练的模型,在对应测试集(后15847个样本)上计算的得分。
  2. 交叉验证完成后,GridSearchCV会自动用全部X和y数据重新训练一个使用最佳参数的模型,这个模型才是你后续调用score、predict_proba时使用的模型。
  3. 全量数据训练的模型拟合能力更强,在测试集上的表现自然优于仅用一半数据训练的模型,所以得分更高。

验证与解决

如果想让后续计算的分数和交叉验证过程中的一致,可以设置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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.18 21:25:05