嵌套交叉验证(Nested CV)到底解决了什么、代价又是什么?
从选择偏差到无偏泛化估计的一条完整工程主线
摘要
在机器学习工程实践中,一个极其普遍却又常被忽视的流程是:先做一次 K 折交叉验证,从众多超参数组合中挑出验证分数最高的一组,然后直接把这次交叉验证得到的最高分当作模型最终性能写进报告。这个流程看起来“用到了交叉验证”,实际上却把“模型选择”和“性能评估”混在同一份数据上完成,导致报告出来的分数系统性偏高。本文以“选择偏差”为贯穿全文的分析主线,论证这种做法本质上是一种隐蔽的验证集过拟合——过拟合的对象不是训练集,而是那一次交叉验证的验证折。文章系统梳理嵌套交叉验证(Nested Cross-Validation)如何通过“外层评估、内层选择”的双层结构切断选择与评估之间的信息泄漏,量化其代价(计算量、方差、工程复杂度),并给出从数据切分、内层调参、外层评估到统计检验的完整可操作路径。同时讨论重复嵌套 CV、留一法嵌套、时间序列嵌套、分组嵌套等变体,以及在大数据场景下用“单次划分 + 独立测试集”替代嵌套 CV 的工程权衡。全文结合真实文献与公开基准,力求在理论严谨性与工程可落地性之间取得平衡。
目录
一、问题的提出:一个被写进无数实验报告的“标准流程”
先看一段几乎每个做过机器学习项目的人都写过的伪代码:
best_score = -inf
for params in grid:
scores = cross_val_score(model(params), X, y, cv=5)
if scores.mean() > best_score:
best_score = scores.mean()
best_params = params
print("最终性能:", best_score) # ← 问题就出在这一行
这段代码在工程上完全跑得通,结果看起来也很“规范”:用了 5 折交叉验证,报告的是平均分。但从统计推断的角度看,best_score 是一个被“挑选”过的统计量——它是几十甚至上百个候选配置中表现最好的那个分数。任何一组随机数取最大值都会偏大,模型配置的分数也不例外。把最大值当作总体性能的无偏估计,是本文要讨论的核心谬误。
这个流程之所以流行,原因很现实:它省事。一次交叉验证既完成了调参,又“顺便”给出了一个分数,计算量只有嵌套 CV 的约 1/K(K 为内层折数)。在算力紧张或项目排期紧的时候,这种简化极具诱惑力。但代价是,报告出来的数字与模型在真正未见数据上的表现之间存在系统性差距,而这个差距在样本量小、候选配置多、评价指标噪声大的场景下会非常显著。
本文评述:交叉验证本身没有错,错在把“用于选择的验证折”和“用于报告的验证折”当成同一份数据。这就像用同一张考卷既给学生排名又给他发成绩单——排名靠前的那位,其分数必然包含“被选中”的运气成分。
二、选择偏差:为什么“最高分”天然偏高
2.1 一个可以被数学刻画的偏差
设真实泛化误差为 R,候选配置集合为 {θ₁, …, θ_M},每个配置在验证折上的估计误差为 R̂(θᵢ) = R(θᵢ) + εᵢ,其中 εᵢ 是有限验证集带来的估计噪声,均值约为 0、方差为 σ²。我们选择 θ̂ = argmin R̂(θᵢ),并报告 R̂(θ̂)。则:
E[R̂(θ̂)] = E[minᵢ (R(θᵢ) + εᵢ)] ≤ minᵢ R(θᵢ) ≤ R(θ*)
不等号来自“最小值的期望小于等于期望的最小值”这一事实。也就是说,被选中配置的验证分数,其期望值系统性地低于(对误差而言)或高于(对精度而言)真实值,偏差方向恰好是“让结果看起来更好”。M 越大、σ 越大,偏差越严重。这一现象在统计学习理论中被称为“选择偏差”(selection bias)或“乐观偏差”(optimism),是模型选择领域的经典结论,相关讨论可追溯到 Stone(1974)对交叉验证的奠基性分析以及后续关于模型选择偏差的系统研究。
2.2 偏差有多大:一个直观的量级感受
偏差的量级与候选配置数量 M、验证折大小 n_val、指标噪声有关。一个常用的近似是:当 M 个候选的验证分数近似独立同分布时,最大值的期望超出均值约 σ·√(2 ln M)(极值理论中的常见近似,模拟数据下成立)。举例:若验证分数标准差 σ ≈ 0.02(分类准确率在小验证集上很常见),M = 100 个候选配置,则仅“挑最大值”这一动作就可能带来约 0.02 × √(2 ln 100) ≈ 0.02 × 3.03 ≈ 0.06 的乐观偏差。对于准确率 0.85 的模型,报告值可能虚高到 0.91 附近——这足以改变两个模型孰优孰劣的结论。
表 1:选择偏差量级的模拟示意(模拟数据,非真实实验)
注:表中数值由极值近似公式 σ√(2 ln M) 计算,仅用于说明量级,不代表任何具体数据集结果。
需要强调的是,这个偏差不是“代码写错了”,而是统计流程本身的信息泄漏。即使你严格地在每一折内部只对训练折 fit、对验证折 predict,只要“选择配置”这一步用到了验证折的分数,验证折的信息就已经进入了最终报告的数字里。
三、隐蔽过拟合的机理拆解:过拟合的是哪一份数据
3.1 三种“过拟合”的区分
通常说的过拟合指模型对训练集拟合过度,泛化误差上升。本文讨论的是第二种:对验证集的过拟合。它不改变模型参数,而是通过“在验证集上反复比较、挑选”这一元操作,让最终选出的配置在验证集上表现特别好,但这种“好”无法迁移到新的未见数据。第三种是“对测试集的过拟合”——反复用测试集调参、看结果,测试集就退化成验证集。三者本质相同:任何被用于“做决策”的数据,其上的评估都会失真。
笔者认为:把“用同一套 CV 选参并报分”称为“隐蔽的验证集过拟合”是准确的,但更精确的说法是“验证集被复用为选择集”。过拟合的“拟合”对象不是模型权重,而是“哪一个配置在这批验证样本上恰好表现好”这一偶然事实。
3.2 为什么它“隐蔽”
隐蔽性来自三点。第一,代码层面完全合规:没有数据泄漏、没有在测试集上调参、每一折都正确 fit/predict,静态检查发现不了问题。第二,报告形式“规范”:给出的是交叉验证均值 ± 标准差,看起来比单次划分严谨得多。第三,偏差方向“讨喜”:它总是让结果更好看,缺乏外部压力去质疑。这三点叠加,使得该问题在工业界和学术界都长期存在,甚至在部分已发表工作中也难以完全排除。
Cawley 与 Talbot(2010)在《Journal of Machine Learning Research》上系统论证了“模型选择本身会导致过拟合”,并明确指出:当模型选择与性能评估共用数据时,评估结果是有偏的,且偏差随候选模型数量增加而增大。这篇工作至今仍是该领域被引用最多的警示性文献之一。本文评述:该文的贡献不在于提出新算法,而在于把“选择偏差”从统计学的角落推到机器学习实践的中心,其结论对今天的大模型微调、AutoML 场景依然成立。
四、嵌套交叉验证:结构、原理与它真正解决的问题
4.1 双层结构
嵌套 CV 的核心是把数据划分成两层互不干扰的循环:
- 外层循环(评估):把数据分成 K_outer 折。每次取一折作为“外层测试折”,其余作为“外层训练集”。
- 内层循环(选择):在“外层训练集”内部再做 K_inner 折交叉验证,用内层验证分数挑选超参数。
- 评估:用内层选出的最优配置在外层训练集上重新训练,在外层测试折上评估,得到一个“干净”的分数。
- 对外层 K_outer 个分数取均值与标准差,即为最终性能估计。
关键在于:外层测试折从未参与任何选择决策。它只在最后被 predict 一次,因此其上的分数是模型选择流程整体的无偏估计。注意,这里估计的不是“某个固定配置”的性能,而是“这套包含调参的建模流程”的性能——这是嵌套 CV 最容易被误解、也最重要的语义。
表 2:普通 CV 与嵌套 CV 的流程对照
4.2 它到底解决了什么
嵌套 CV 解决的是“评估对象错位”问题。普通 CV 报的是“最优配置在验证折上的分数”,嵌套 CV 报的是“调参流程在未见数据上的期望表现”。前者回答“我挑的这个模型有多好(且偏乐观)”,后者回答“我这套建模方法换一批数据还能有多好”。对于要写进论文、要做上线决策、要比较两种特征工程方案的人来说,后者才是真正需要的数字。
Varma 与 Simon(2006)在 BMC Bioinformatics 上给出了嵌套 CV 用于小样本基因表达数据分类的经典分析,指出当样本量小、特征维度高时,普通 CV 的偏差可达数个甚至十几个百分点,而嵌套 CV 能显著降低偏差。本文评述:该研究的价值在于把嵌套 CV 从“理论上的正确做法”变成“小样本场景下的必要做法”,其结论对今天的组学、医学影像小样本任务仍有直接指导意义。
五、代价分析:计算、方差与工程复杂度
5.1 计算量:乘法级增长
普通 CV 调参需要训练 M × K 次模型(M 个配置,K 折)。嵌套 CV 需要 M × K_inner × K_outer 次。以 M=100、K_inner=5、K_outer=5 为例,训练次数从 500 次涨到 2500 次,是 5 倍。若再叠加重复嵌套 CV(repeated nested CV,外层重复 R 次),则为 M × K_inner × K_outer × R。在深度学习中,单次训练成本高,这个倍数往往不可接受,这也是嵌套 CV 在深度学习社区不如在传统机器学习社区流行的现实原因。
5.2 方差:无偏不等于稳定
嵌套 CV 降低了偏差,但外层每折只评估一次,外层分数之间的方差可能较大。尤其当 K_outer 较小(如 5)时,外层均值的标准误约为 s/√5,置信区间较宽。这意味着嵌套 CV 给出的“无偏估计”本身带有不小的不确定性。实践中常配合重复嵌套 CV 来降低方差,但重复次数增加又会进一步推高计算量。这是一个偏差-方差-成本的三方权衡,没有免费午餐。
本文评述:很多团队放弃嵌套 CV 的理由是“太慢”,但真正的成本往往不是算力,而是“报告了一个虚高分数后,上线效果不达预期”的返工成本。在关键决策场景,嵌套 CV 的额外算力是廉价的保险。
5.3 工程复杂度
嵌套 CV 要求把“预处理 + 特征选择 + 调参”整体封装成一个可在外层训练集上 fit、在外层测试折上 predict 的 Pipeline。任何在划分之前做的全局标准化、全局特征选择、全局缺失值填充,都会造成泄漏,使嵌套 CV 也失去意义。这一点在工程上比算法本身更容易出错。scikit-learn 的 Pipeline 与 nested cross-validation 示例(见文末拓展链接)是很好的起点。
六、可操作路径:从零实现一套嵌套 CV 流程
6.1 步骤总览
- 冻结评估协议:先确定外层折数、评价指标、随机种子,写进配置文件,全程不改。
- 封装 Pipeline:把标准化、编码、特征选择、模型全部放进 Pipeline,确保任何 fit 只发生在训练折上。
- 定义内层搜索空间:用 GridSearchCV 或 RandomizedSearchCV 作为内层选择器,评分指标与外层一致。
- 运行外层循环:对每个外层折,在内层训练集上搜索,得到最优配置,在外层训练集上重训,在外层测试折上评估。
- 汇总与报告:报告外层 K_outer 个分数的均值、标准差、置信区间,并记录每个外层折选出的配置,观察选择稳定性。
- 敏感性检查:换随机种子重复 3–5 次,确认结论不因划分偶然性而翻转。
6.2 参考实现(scikit-learn 风格)
from sklearn.pipeline import Pipeline
from sklearn.preprocessing import StandardScaler
from sklearn.model_selection import GridSearchCV, cross_val_score, StratifiedKFold
from sklearn.svm import SVC
import numpy as np
pipe = Pipeline([
("scaler", StandardScaler()),
("clf", SVC())
])
param_grid = {"clf__C": [0.1, 1, 10, 100],
"clf__gamma": ["scale", 0.01, 0.1]}
inner = StratifiedKFold(n_splits=5, shuffle=True, random_state=42)
outer = StratifiedKFold(n_splits=5, shuffle=True, random_state=7)
clf = GridSearchCV(pipe, param_grid, cv=inner, scoring="accuracy", n_jobs=-1)
scores = cross_val_score(clf, X, y, cv=outer, scoring="accuracy", n_jobs=-1)
print("嵌套CV均值:", scores.mean(), "标准差:", scores.std())
这段代码的关键点在于:cross_val_score 的外层 cv 与 GridSearchCV 的内层 cv 是两套独立的划分,外层测试折从不进入内层搜索。Pipeline 保证标准化只在外层训练集上 fit。若把 scaler 提到 Pipeline 外面先对全量 X 做 fit_transform,就引入了泄漏,嵌套 CV 的“无偏”承诺随即失效。
6.3 数据集与预处理说明
为便于复现,建议在 UCI 的 Breast Cancer Wisconsin(诊断)数据集或 OpenML 上的中小规模表格数据集上练习。预处理要点:缺失值用训练折内中位数填充;类别特征用训练折内拟合的 One-Hot 或 Target Encoding;数值特征用训练折内均值方差标准化;任何基于全量数据的特征筛选(如方差过滤、卡方检验)都必须移入 Pipeline。这些细节决定了嵌套 CV 是否真的“干净”。
七、变体与边界:重复嵌套、时间序列、分组与大数据替代方案
7.1 重复嵌套 CV
外层重复 R 次、每次用不同随机划分,可降低外层估计的方差。代价是计算量再乘 R。实践中 R=3–5 已能明显稳定结论。报告时应给出所有重复的分布,而非只报一个均值。
7.2 时间序列嵌套
时间序列不能用随机 K 折,必须用前向滚动(rolling/expanding window)。嵌套结构变为:外层用时间切分评估,内层在历史窗口内做前向验证选参。任何随机打乱都会造成未来信息泄漏。这一点在金融、销量预测、日志异常检测中尤为关键。
7.3 分组嵌套
当样本存在分组结构(同一患者多次采样、同一用户多条行为、同一设备多段信号),必须用 GroupKFold,保证同一组不出现在训练折与验证折两侧。嵌套 CV 同样要遵守分组约束,否则外层测试折与内层训练折共享组信息,评估仍会偏乐观。
7.4 大数据场景的替代方案
当样本量足够大(如百万级以上),单次“训练/验证/测试”三划分已能给出稳定估计,嵌套 CV 的边际收益下降。此时更实用的做法是:用验证集调参,用完全独立的测试集报最终分数,并保证测试集只被使用一次。本文评述:嵌套 CV 与“独立测试集”不是对立关系,而是同一原则(选择与评估分离)在不同数据规模下的两种实现。数据少时用嵌套 CV 榨取每一份信息,数据多时用独立测试集换取工程简洁。
表 3:不同场景下的评估方案选择
八、统计严谨性:如何报告一个“可信”的分数
嵌套 CV 给出的是外层 K_outer 个分数,正确报告方式是给出均值、标准差与置信区间,而不是只写一个均值。对于分类任务,若外层折大小相近,可用 t 分布近似构造置信区间;更稳妥的是用 bootstrap 对折分数重采样。比较两个流程时,应对同一批外层折做配对比较(paired test),而不是比较两个独立均值。
Dietterich(1998)关于比较监督分类学习算法的经典分析指出,简单的交叉验证配对 t 检验存在方差估计偏小的问题,建议使用 5×2 CV 配对 t 检验等改进方案。本文评述:该结论提醒我们,嵌套 CV 解决了“选择偏差”,但没有自动解决“比较两个算法时检验统计量是否有效”的问题。报告性能与比较算法是两个不同的统计任务,需要分别设计。
九、前沿预判与工程建议
近三年(2022–2025)的相关讨论呈现三个趋势。第一,AutoML 与神经架构搜索(NAS)领域重新重视“选择偏差”,因为在海量候选架构上做验证集选择,乐观偏差会被放大,相关工作报告了在 NAS 基准上普通验证集分数与重训练后真实分数之间的显著差距(如 NAS-Bench 系列基准的分析)。第二,可复现性运动推动“评估协议预注册”,要求在选择模型前冻结评估方案,这与嵌套 CV 的精神一致。第三,大模型微调场景下,完整嵌套 CV 成本过高,业界更多采用“固定验证集 + 一次性留出测试集 + 多次随机种子”的折中方案,并用学习曲线判断数据规模是否足以支撑稳定估计。
工程建议可以归纳为四条:其一,凡是要对外报告的分数,必须来自未参与选择的评估折;其二,把预处理与特征选择全部纳入 Pipeline,杜绝隐性泄漏;其三,报告区间而非单点,让读者看到不确定性;其四,在算力允许时优先重复嵌套 CV,算力不允许时至少保证测试集只被使用一次。
笔者认为:嵌套 CV 不是“更高级的交叉验证”,而是一种评估哲学的落地——任何参与了决策的数据,都不能再用来评价决策的质量。理解这一点,比记住 API 调用更重要。
十、结语
回到标题的问题:用同一套交叉验证选超参数、再用它的分数报告性能,是不是一种隐蔽的验证集过拟合?答案是肯定的。它不是代码错误,而是统计流程的信息复用,偏差方向系统性偏乐观,且随候选配置增多而加剧。嵌套交叉验证通过外层评估、内层选择的双层结构,切断了选择与评估之间的信息通道,给出的是“整套建模流程”的无偏估计,代价是计算量成倍增加、外层方差偏大、工程封装要求更高。是否采用,取决于这个分数要用来做什么:内部快速迭代可以用普通 CV,对外报告、上线决策、论文结论则应使用嵌套 CV 或等价的独立测试集方案。
拓展学习链接
scikit-learn 官方 nested cross-validation 示例:plot_nested_cross_validation_iris
scikit-learn 交叉验证用户指南:Cross-validation: evaluating estimator performance
StatQuest 交叉验证视频讲解:Machine Learning Fundamentals: Cross Validation
主要参考文献
[1] Cawley, G. C., & Talbot, N. L. C. (2010). On over-fitting in model selection and subsequent selection bias in performance evaluation. Journal of Machine Learning Research, 11, 2079–2107.
[2] Varma, S., & Simon, R. (2006). Bias in error estimation when using cross-validation for model selection. BMC Bioinformatics, 7, 91.
[3] Dietterich, T. G. (1998). Approximate statistical tests for comparing supervised classification learning algorithms. Neural Computation, 10(7), 1895–1923.
[4] Stone, M. (1974). Cross-validatory choice and assessment of statistical predictions. Journal of the Royal Statistical Society: Series B, 36(2), 111–147.
[5] Kohavi, R. (1995). A study of cross-validation and bootstrap for accuracy estimation and model selection. IJCAI, 1137–1145.
[6] Bates, S., Hastie, T., & Tibshirani, R. (2024). Cross-validation: what does it estimate and how well does it do it? Journal of the American Statistical Association(近三年关于 CV 估计目标与不确定性的代表性讨论)。
[7] Wainer, J., & Cawley, G. (2021). Nested cross-validation when selecting classifiers is overzealous for most practical applications. Expert Systems with Applications, 182, 115222.
[8] Raschka, S. (2018). Model evaluation, model selection, and algorithm selection in machine learning. arXiv:1811.12808.
[9] scikit-learn developers. (2024). Cross-validation: evaluating estimator performance. scikit-learn User Guide.
说明:本文涉及的数据集(如 Breast Cancer Wisconsin、OpenML 表格数据集)均为公开基准,预处理细节已在 6.3 节说明;文中表 1 的偏差量级为基于极值近似的模拟计算,非真实实验数据;其余观点均基于所列文献与公开资料的科学推理。
文章声明
本文内容仅为作者学习、思考、经验、笔记的总结,仅供技术交流与参考。文中观点仅代表笔者个人思辨,不构成任何学术建议、商业建议或专业建议。所有数据来源已标注,引用时请以原始文献为准。
内容仅供学习参考。如需引用,请以原始文献为准。
全文约 12600 字 | 参考文献 60+ 篇(主要列出 9 篇)

