GridSearchCV(refit='accuracy')混淆矩阵数值与平均准确率不匹配问题
问题:GridSearchCV全量数据准确率与交叉验证均值不一致
我在使用GridSearchCV时设置了多评估指标,指定refit='accuracy'参数。由于refit会基于全量数据集重新训练模型,交叉验证各折的混淆矩阵或AUC曲线并无实际意义。但当我用全量数据集生成混淆矩阵后,通过(TP+TN)/总样本计算得到的准确率,与模型训练得到的mean_test_Accuracy数值不一致,不清楚遗漏了什么环节。
相关代码如下:
scoring = {'Accuracy':'accuracy','AUC': 'roc_auc'} CV = StratifiedKFold(n_splits = 4, random_state = None, shuffle=True) pipe = Pipeline([('transform', SimpleImputer(strategy='mean')), ('kbest', SelectKBest(f_classif)), ('classifier', SVC())]) search = GridSearchCV( estimator = pipe, param_grid = param_grid, refit= 'Accuracy', n_jobs=-1, scoring=scoring, cv=CV, verbose=0, error_score='raise' ) search.fit(X, y) df=pd.DataFrame(search.cv_results_) df=df.sort_values('rank_test_Accuracy') val_acc = df['mean_test_Accuracy'].iloc[0]
全量数据混淆矩阵计算代码:
from sklearn.metrics import confusion_matrix y_pred = search.best_estimator_.predict(X) print (confusion_matrix(y, y_pred))
核心原因分析
- 计算对象不同:
mean_test_Accuracy是4折交叉验证中,每折验证集准确率的平均值,反映的是模型在未见过的陌生数据上的泛化能力;而全量数据的准确率是模型在所有训练+验证数据上的表现,包含了模型已经学习过的信息,两者数值本就应该存在差异。 - 特征选择的数据集依赖性:你的Pipeline包含
SelectKBest,这个步骤会基于当前训练数据的F值筛选特征。交叉验证时,每折都会用该折的训练集重新计算特征优先级;而refit后的模型是用全量数据做的特征选择,两次筛选出的特征子集大概率不同,这会进一步放大准确率的差异。
验证方法
1. 手动复现交叉验证均值
通过手动模拟交叉验证过程,验证mean_test_Accuracy的计算逻辑:
import numpy as np from sklearn.metrics import accuracy_score cv_scores = [] for train_idx, val_idx in CV.split(X, y): X_train, X_val = X.iloc[train_idx], X.iloc[val_idx] y_train, y_val = y.iloc[train_idx], y.iloc[val_idx] # 使用最优参数训练当前折模型 pipe.set_params(**search.best_params_) pipe.fit(X_train, y_train) y_pred_val = pipe.predict(X_val) cv_scores.append(accuracy_score(y_val, y_pred_val)) manual_mean_acc = np.mean(cv_scores) print(f"手动计算的交叉验证均值:{manual_mean_acc:.4f}") print(f"GridSearchCV输出的mean_test_Accuracy:{val_acc:.4f}")
两者数值应该完全一致,说明交叉验证的计算逻辑没问题。
2. 对比特征选择结果
查看全量数据训练的模型和交叉验证单折模型的特征选择差异:
# 查看refit模型选中的特征 refit_kbest = search.best_estimator_.named_steps['kbest'] refit_selected = refit_kbest.get_support() # 查看交叉验证第一折模型选中的特征 train_idx, val_idx = next(CV.split(X, y)) X_train = X.iloc[train_idx] pipe.set_params(**search.best_params_) pipe.fit(X_train, y.iloc[train_idx]) cv_kbest = pipe.named_steps['kbest'] cv_selected = cv_kbest.get_support() print(f"全量数据与交叉验证折的特征选择是否一致:{np.array_equal(refit_selected, cv_selected)}")
大概率会输出False,这就是造成准确率差异的关键因素之一。
结论
这种差异是正常且合理的:
mean_test_Accuracy是模型泛化能力的可靠估计,代表模型在新数据上的表现;- 全量数据准确率是模型在训练数据上的拟合结果,数值通常会更高,仅能反映模型对现有数据的学习程度,不能代表泛化能力。
内容的提问来源于stack exchange,提问作者sam
相关产品推荐
相关产品推荐

