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

KNN、LR、MLP模型嵌套与非嵌套CV结果一致问题咨询

嵌套与非嵌套K折交叉验证结果异常排查

问题背景

我使用K-fold嵌套与非嵌套交叉验证(Nested vs Non-nested CV)检测分类模型是否存在过拟合,代码参考自scikit-learn官方示例。由于两类交叉验证采用随机数据划分方式,预期结果应存在差异,例如随机森林的对比结果符合预期:

随机森林非嵌套与嵌套交叉验证对比图

异常现象

但KNN、逻辑回归、多层感知机(MLP)三类模型在25次试验中,嵌套与非嵌套交叉验证的结果完全一致:

KNN非嵌套与嵌套交叉验证对比图
逻辑回归非嵌套与嵌套交叉验证对比图
多层感知机非嵌套与嵌套交叉验证对比图

代码问题分析

从提供的代码来看,核心错误和问题点如下:

1. 嵌套CV传入已拟合的模型实例

在CVNCV_organiser函数中,非嵌套部分先调用nn_clf.fit(X, y)训练了GridSearchCV(默认refit=True,会用最优参数在全量数据上训练模型),随后将这个已拟合完成的模型传给cross_validate做嵌套CV。这完全违背了嵌套CV的逻辑:

  • 嵌套CV的核心是在每个外层折中,先在训练子集上做内层参数搜索+训练,再在测试子集上评估;
  • 传入已拟合的模型后,cross_validate不会重新执行参数搜索,直接用已训练好的模型在各折测试集上预测,导致结果和非嵌套的best_score_(基于内层CV的训练集评估)异常一致。

2. 参数网格无搜索空间

以MLP的参数网格为例:

hparams_MLP = {'model__activation': ['identity'],
              'model__solver': ['sgd'],
              'model__learning_rate': ['constant'],
              'model__hidden_layer_sizes': [(21,17)],
              'model__tol': [0.00034]}

每个参数都只有一个可选值,GridSearchCV本质上等价于普通交叉验证,没有进行参数调优。而非嵌套CV和嵌套CV的差异核心正是参数调优带来的过拟合——当没有参数搜索空间时,两者的评估逻辑几乎一致,自然会出现结果重合的情况。

3. 变量作用域不严谨

循环中重新定义了inner_cv和outer_cv,但函数CVNCV_organiser直接使用全局变量,虽然不会直接导致结果一致,但代码结构不严谨,容易引发其他逻辑问题。

修复建议

1. 修正嵌套CV的实现逻辑

在嵌套CV中,传入未拟合的GridSearchCV实例,而非已拟合的模型。修改CVNCV_organiser函数:

def CVNCV_organiser(classifier, p_grid, inner_cv, outer_cv, nnscorelist, nscorelist, i):
    # 非嵌套CV:全量数据上做参数搜索+评估
    nn_clf = GridSearchCV(estimator=classifier, param_grid=p_grid, cv=inner_cv)
    nn_clf.fit(X, y)
    nnscorelist[i] = nn_clf.best_score_
    
    # 嵌套CV:外层CV的每个折中独立做内层参数搜索+评估
    # 传入未拟合的GridSearchCV实例,cross_validate会自动在各折处理
    nested_clf = GridSearchCV(estimator=classifier, param_grid=p_grid, cv=inner_cv)
    scores = cross_validate(nested_clf, X, y, cv=outer_cv, scoring=scoring, return_train_score=True)
    nscorelist.append(scores)

2. 扩展参数网格的搜索空间

给每个参数设置多个可选值,让GridSearchCV真正进行参数调优,例如修改MLP的参数网格:

hparams_MLP = {'model__activation': ['identity', 'relu'],
              'model__solver': ['sgd', 'adam'],
              'model__learning_rate': ['constant', 'adaptive'],
              'model__hidden_layer_sizes': [(10,), (21,17), (30,)],
              'model__tol': [1e-4, 3.4e-4, 1e-3]}

3. 优化循环中的变量传递

将inner_cv和outer_cv作为参数传入函数,避免全局变量依赖:

for i in range(trials):
    inner_cv = KFold(n_splits=4, shuffle=True, random_state=i)
    outer_cv = KFold(n_splits=4, shuffle=True, random_state=i)

    CVNCV_organiser(MLP_clf_pipeline, hparams_MLP, inner_cv, outer_cv, 
                    MLP_non_nested_scores, MLP_nested_scoring, i)
    
    MLP_nested_scores[i] = MLP_nested_scoring[i]['test_accuracy'].mean()

内容的提问来源于stack exchange,提问作者IbbyR

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.08 10:35:58