
在机器学习中,最终目标是构建不仅在训练数据上表现良好,而且在未见过的新数据上同样表现出色的模型。这种泛化能力是衡量模型价值的真正标准,然而,要获得对此性能的真实估计却是一项巨大的挑战。简单的验证方法可能会陷入一个微妙的陷阱,尤其是在我们调整模型超参数时,这会导致一种“乐观者诅咒”,即报告的性能高得具有欺骗性。本文将直面这个有偏评估的关键问题。
接下来的章节将引导您了解黄金标准的解决方案。首先,在“原理与机制”一章中,我们将剖析标准交叉验证为何会失败,解释乐观偏差的概念,并介绍嵌套交叉验证的优雅架构,它能提供可信的性能估计。随后,“应用与跨学科联系”一章将展示该方法深远的重要性,探讨其在预防医学诊断等高风险领域灾难性错误中的关键作用,以及它在气候科学等领域对不同数据结构的适应。
在我们构建能够预测、分类或揭示隐藏模式的模型的过程中,一个问题比其他任何问题都更为重要:“我们的模型真的好用吗?”模型仅仅在用于构建它的数据上表现良好是不够的;这就像一个学生在看过答案后在考试中取得优异成绩一样。对模型的真正考验是其在未见过的新数据上的性能。这种在从未遇到过的数据上表现良好的能力称为泛化(generalization)。我们所有的努力都取决于能否诚实地估计它。
为我们的模型获得真实评分的最直接方法是从一开始就预留一部分数据。我们将数据划分为两个集合:一个训练集(training set),我们用它来教导我们的模型;一个测试集(test set),我们将其锁起来。一旦模型完全训练好,我们再解锁测试集,看看它的表现如何。这种训练-测试集划分是验证最简单的形式,它体现了将训练与评估分开的基本原则。
但这种简单的方法也有其自身的问题。通过预留测试集,我们没有使用所有宝贵的数据来构建最好的模型。而且,如果我们划分数据时运气不好怎么办?也许测试集纯粹是偶然地包含了所有简单案例,使我们的模型看起来像个天才,或者包含了所有困难案例,使其看起来像个傻瓜。
为了克服这个问题,我们可以使用一种更巧妙的程序,称为 k-折交叉验证(CV)。想象我们有一副代表我们数据的扑克牌。我们不是一次性划分,而是将这副牌分成(比如说)个相等的部分,或称为“折”(folds)。然后我们进行十次独立的实验。在第一次实验中,我们使用第一折作为测试集,其他九折作为训练集。在第二次实验中,我们使用第二折作为测试集,其他九折用于训练。我们持续这个过程,直到每一折都有机会成为测试集。通过对这十次实验的性能取平均,我们得到了一个更稳健、更稳定的模型性能估计,这个估计使用了每一个数据点进行训练和测试,只是从未在同一时间使用。
k-折交叉验证似乎是一个非常完美的解决方案。如果你只有一个固定的模型,它确实如此。但如果你的模型有可以调整的旋钮呢?这些被称为超参数(hyperparameters)。对于支持向量机,这可能是正则化参数 ;对于 LASSO 回归,这是收缩惩罚 ;对于复杂的医疗流程,它甚至可能是要选择的特征数量。我们希望找到能产生最佳模型的设置。
于是,一个自然的想法出现了:让我们用我们可靠的 k-折交叉验证来测试一系列的超参数设置。我们为每个设置运行整个 CV 过程并得到一个分数。我们查看所有的分数,挑选最高的一个,然后庆祝。“我们的模型准确率达到 95%!”我们自豪地报告我们找到的最高分。
就在那庆祝的时刻,我们陷入了一个微妙而深刻的陷阱。我们成了乐观者诅咒(optimist's curse)的受害者。
想象你是一位老师,给十个根本没复习的学生进行一场有 100 道是非题的考试。他们都在瞎猜。平均来说,你期望每个学生得分在 50% 左右。但由于随机运气,一个学生可能答对 58 道,另一个可能答对 45 道,等等。如果你查看所有分数,挑出最高分(58分),并宣称这个学生“知识水平为 58%”,那你就是在自欺欺人。你把一次幸运的猜测误认为是真正的能力。这个错误也被称为“赢家诅咒”(winner's curse)。搜索最佳结果并将其作为性能估计值的行为会产生乐观偏差(optimistic bias)。
从统计学上讲,这种情况的发生是因为每个交叉验证分数都是该超参数真实性能的一个带噪声的估计。当我们从一组带噪声的估计中取最大值时,我们实际上是在选择那个从正向噪声中获益最多的估计。一组随机变量最大值的期望总是大于或等于它们期望的最大值,或者对于我们希望最小化的损失函数,。这个简短的数学公式是我们“诅咒”的正式表述。这种膨胀并非微不足道;对于一个中等复杂度的搜索,它可以将一个真实值为 60% 的报告准确率夸大到超过 65% 的表观值,这是一个显著且具有误导性的跳跃。
为了得到一个诚实的估计,我们需要一个模仿现实的程序:你首先开发你的模型,然后在全新的数据上测试它。我们如何用单一数据集模拟这个过程?答案是一个优雅而强大的思想,称为嵌套交叉验证(nested cross-validation)。
可以把它想象成创建一个“实验室中的实验室”。
嵌套交叉验证的外层循环(outer loop)代表真实世界和我们最终的、诚实的评估。它像标准 CV 一样将数据划分为 折。在每次迭代中,它将一折数据作为原始的、未被触碰的外层测试集(outer test set)保留下来。
剩下的 折成为内部实验室(inner lab)(即外层训练集)。在这个密封的实验室内,我们可以随心所欲地进行实验。我们运行另一个完全独立的交叉验证——内层循环(inner loop)——且仅在实验室内部的数据上进行。这个内层 CV 用于完成我们所有的调优工作:我们测试每一个超参数,比较不同的模型,并选出在实验室内表现最佳的冠军配置。
一旦内部实验完成,我们得到了获胜的超参数集,我们执行最后一步:我们使用这个获胜的配置在整个实验室数据集(所有 个外层训练折)上训练一个模型。然后,我们用这个单一的、最终的模型,在那个一直等待在外面、未被触碰的原始外层测试集上进行一次且仅一次的评估。
我们对所有 个外层折重复这整个过程。最终的性能估计是来自 个外层测试集分数的平均值。这个最终数字不是单个模型的性能,而是我们整个建模流程(包括数据驱动的超参数选择步骤)性能的近乎无偏的估计。它回答了正确的问题:“如果我将这整套方法论应用于新数据,我可以期待什么样的性能?”
让我们通过一个具体的例子来看。想象一个团队使用了一个有缺陷的“朴素”程序,他们直接在测试折上挑选最佳超参数。他们可能会发现,他们的三个折的测试 AUC 值分别为 0.79、0.80 和 0.77,平均得到一个很有希望的 0.787。然而,当他们遵循正确的嵌套 CV 协议时,内层循环在看到测试集之前就选出了最佳超参数。在原始外层测试集上得到的最终分数是 0.77、0.76 和 0.77,得出一个更现实的平均值 0.767。这 0.02 的差异就是通过嵌套设计消除的乐观偏差。
嵌套交叉验证所强制执行的分离原则比仅仅是超参数调优更深。许多机器学习流程在模型训练之前涉及多个依赖数据的步骤。例如,我们可能:
同样的“乐观者诅咒”适用于所有这些步骤。如果你使用整个数据集计算用于归一化的均值和标准差,或者如果你使用整个数据集上的统计检验来选择“最佳”特征,你就已经犯了一个根本性的错误。来自测试集的信息已经“泄漏”到你的训练过程中。你的模型已经(即使是间接地)偷看到了考题。
一个真正严格的嵌套交叉验证流程将每一个依赖数据的步骤都封装在内层循环中。对于每个外层折,标准化、特征选择和超参数调优的过程都只使用外层训练数据从头开始重新学习。这可以防止任何信息泄漏,并确保最终评估是真正无偏的。忽略这一点的后果可能是戏剧性的。在医学标志物研究中,一个泄漏的流程可能会报告一个 0.90 的出色 AUC,暗示着一个近乎完美的诊断测试。而在相同数据上正确嵌套的流程可能会揭示一个更为清醒的 AUC,仅为 0.68——这是感知到的突破与对一个温和效应的现实评估之间的差异。
这种科学的严谨性并非没有代价。嵌套交叉验证的计算成本很高。考虑一个设置,其中有 的外层循环,一个 的内层循环, 种超参数组合,以及为稳定选择而重复 次的内层 CV。模型训练的总次数不是 5 或 10 次;而是惊人的 次独立训练。这代表了计算预算和结果可信度之间的一个重要权衡。
那么,为什么不直接使用我们开始时提到的简单训练-测试集划分呢?它当然更快。原因在于精度(precision)。虽然单次训练-测试集划分提供了一个无偏的估计,但其方差很高——它对你所做的特定划分非常敏感。嵌套 CV 通过最终使用每个数据点进行测试,平均掉了这种可变性。其最终估计是基于完整数据集的,使其更加稳定和精确。在一个简化的理论模型中,如果你使用 60/40 的训练/测试集划分,你的性能估计的方差比在相同数据上的嵌套 CV 估计的方差高出惊人的 2.5 倍。你通过更有效地利用数据来获得精度。
对于这种可变性成为主要问题的小数据集,我们可以更进一步,执行重复嵌套交叉验证(repeated nested cross-validation)。整个嵌套过程使用不同的数据初始随机洗牌运行多次,然后将结果平均。这不会改变偏差,但会进一步降低最终估计的方差,为我们提供关于模型真实能力的更可靠的画面。
最终,这个原则简单而优美:要发现你真正知道什么,你必须用你从未见过的问题来测试自己。在机器学习的世界里,嵌套交叉验证是这一永恒智慧最忠实、最严谨的体现。它是诚实模型评估的黄金标准。
掌握了嵌套交叉验证的优雅机制后,我们可能会倾向于将其视为一种巧妙但小众的统计技巧。事实远非如此。实际上,追随这个思想的轨迹,我们将踏上一段跨越现代科学版图的非凡旅程,从解码人类基因组到预测地球气候。它揭示了一个科学诚信的普适原则,是任何试图从复杂数据中学习的领域的行为准则。让我们踏上这段旅程,看看这一个概念如何为我们应对这个时代一些最具挑战性的问题提供指南。
我们的旅程始于新兴的基因组学(genomics)和放射组学(radiomics)领域,这些领域饱受一个有趣而危险的问题的困扰,这个问题通常被称为“维度灾难”(curse of dimensionality)。想象你是一位医学研究者,拥有一份包含(比如说)80 名患者的数据集。对于每位患者,你都有海量的数据——也许是 20,000 个基因的表达水平,或是从医学扫描中提取的数千个纹理特征。你的目标是找出这数千个特征中哪些可以预测患者是否患有某种疾病。
由于特征如此之多而患者如此之少,你的数据集是一个广阔而稀疏的空间。这就像处在一个巨大的、黑暗的房间里,只有几十个分散的光点。在这个高维世界里,一种奇特而危险的魔法发生了:纯粹通过偶然性找到模式变得惊人地容易。一个灵活的机器学习模型,只要有足够多的特征可以玩弄,几乎总能找到它们的某种组合,在你的样本中完美地将“疾病”组与“对照”组分开。它变成了一个狡猾的机会主义者,利用你特定 80 名患者的随机噪声和怪癖来获得满分。但这种表面的成功是一种幻觉,是一座纸牌屋,一旦遇到新患者就会崩塌。模型没有学到生物学真理;它只是记住了噪声。这就是过拟合(overfitting)的幽灵,而严格的验证是我们唯一的驱魔仪式。
那么,我们如何构建一个可以信任的模型呢?显而易见的第一步是测试它。我们使用交叉验证,保留一部分数据作为“测试集”,看看模型在它未曾训练过的数据上表现如何。但这里存在一个微妙而普遍的陷阱——一系列错误,它们都归结为同一个根本性的错误:在考试结束前偷看答案。
考虑一种常见的方法。我们的模型有一个“调节旋钮”,比如控制其复杂度的正则化参数 。我们想找到这个旋钮的最佳设置。于是,我们为十几个不同的 设置运行交叉验证。我们发现其中一个设置,我们称之为 ,给出了最佳的交叉验证性能。我们得意地宣称,这就是我们模型的真实性能。
但我们欺骗了自己。每个 的交叉验证分数都只是估计值,是带有自身噪声的随机变量。通过选择这些带噪声估计的最小值,我们几乎肯定挑选了在我们的特定数据划分上“最幸运”的那个。报告的性能是一个乐观的幻想。这就像一个侦探利用犯罪现场的线索来决定首先调查哪些线索;当然,那些线索会显得格外重要!为了得到一个诚实的估计, 的选择必须在验证的内层循环中进行,与提供最终、无偏结论的外层循环测试集完全分开。这是嵌套交叉验证的精髓,在医学诊断这个高风险的世界里,这是不容商量的。
这种错误的一种更严重、更常见的形式发生在特征选择期间。面对 20,000 个基因,研究人员可能会首先对整个数据集运行统计检验,以找到与疾病最相关的 50 个基因。然后,他们带着这个“有前途”的 50 个基因子集,继续进行适当的交叉验证来构建和评估他们的模型。
这是一个灾难性的方法论缺陷。通过使用整个数据集的标签来选择特征,研究人员已经让“测试”数据影响了模型的构建。信息已经泄漏,测试集不再是原始的。随后的交叉验证是一场闹剧,它是在一组因其在待测数据上表现良好而被预选的特征上进行的。最终的性能将是极度、面目全非的乐观。这通常被称为目标泄露(target leakage)。唯一诚实的方法是在交叉验证的每一折内部重新执行特征选择步骤,并且只使用该折的训练数据。
这个原则远远超出了这两个例子。建模过程中每一个从数据中学习的步骤都必须包含在验证循环内。“模型”不仅仅是最终的分类器;它是整个分析流程(analytical pipeline)。
例如,在梯度提升模型中,一种常用技术是“早停法”(early stopping),即我们在一定数量的迭代后停止训练以防止过拟合。这个迭代次数是一个超参数,就像 一样。它必须在内层交叉验证循环中进行调优,而不是通过偷看测试集的性能来确定。
一个更微妙的例子出现在多中心医学研究中。来自不同医院的数据通常由于设备或方案的差异而存在“批次效应”(batch effects)。一个常见的预处理步骤是协调化(harmonization),即我们估计并移除这些特定于地点的变异。但是,用于这种协调化的参数——即对每家医院的调整——是从数据中学习的。如果我们在交叉验证之前从整个数据集中学习这些参数,我们又一次犯了根本性的错误。关于测试集分布的信息已经泄漏到训练过程中。协调化过程本身必须是嵌套流程的一部分,在每个训练折内重新学习。
这个原则是如此通用,以至于它能优雅地适应更复杂的架构,例如旨在同时预测多个结果的多任务学习模型(例如,从一个放射组学特征集预测多个基因突变)。关键在于简单地识别出真正的独立单元(unit of independence)——即患者——并确保验证的数据划分始终在该层面进行。来自单个患者的所有数据必须要么属于训练集,要么属于测试集,绝不能同时属于两者。在这个有效的结构内,为每个任务调优超参数的嵌套过程与之前一样进行。
有人可能会认为,这种对数据泄漏的执着是生物医学研究的怪癖,因为其数据维度臭名昭著地高。但这个原则是普适的。让我们离开医院,来到一位环境科学家的世界,他正试图建立一个统计模型,根据大规模气候模式来预测局部降雨量。
在这里,数据不是独立患者的集合,而是一个时间序列,今天的气象与昨天的气象高度相关。使用标准交叉验证进行随机洗牌将是灾难性的。这就像试图通过在周一、周三和周五的数据上训练,然后在周二和周四上测试来预测股市。模型可以非法地偷窥到紧邻的未来和过去,使其工作变得过于容易。
解决方案是在保留原则的同时调整实现方式。科学家不使用随机折,而是使用分块交叉验证(blocked cross-validation)。数据被分割成连续的时间块——例如,在第 1-8 年上训练,在第 9 年上测试;然后在第 1-7 年和第 10 年上训练,在第 8 年上测试。这尊重了数据的时间结构。当然,如果科学家也在选择预测变量或调整模型超参数,这必须在一个嵌套的、分块的交叉验证方案中完成。分离模型选择与性能估计的核心思想保持不变;只是其实现方式改变以适应数据的结构。
我们已经看到同样的想法以不同的伪装出现在不同的领域。这通常是一个迹象,表明我们正在触及一个深刻而根本的真理。让我们最后一次放大视野,看看其背后美丽的、统一的结构。
信息泄露的持续风险以及由此导致的性能声明虚高不仅仅是学术问题。在临床医学中,一个承诺高准确率但在实践中失败的模型可能会产生生死攸关的后果。这促使了报告指南的制定,如 TRIPOD(个体预后或诊断的多变量预测模型的透明报告)及其针对机器学习的扩展 TRIPOD-ML。
这些指南是我们讨论过的统计原则的实践体现。它们是科学诚信的清单,迫使研究人员确切地报告他们的模型是如何开发和验证的。他们是否进行了特征选择?如果是,它是否在交叉验证循环内?超参数是如何调优的?是嵌套程序吗?通过要求在这些关键细节上的透明度,TRIPOD-ML 迫使数据泄露问题暴露在公众面前,让科学界能够评估模型报告的性能是可信的估计还是乐观的幻想。
对嵌套交叉验证为何如此重要的最深刻理解来自一个意想不到的领域:因果推断(causal inference)。我们可以用一个有向无环图(DAG)来表示模型构建过程,其中箭头表示因果影响。超参数选择 会导致拟合模型 的变化,而这又会影响验证性能指标 。同时,真实的验证结果 也会影响 。这在 处创建了一个称为对撞节点(collider)的结构:
在因果图中,这条路径通常是阻塞的; 和 是独立的。然而,当我们选择最大化 的 值时,我们正在“在对撞节点上施加条件”。这个行为打开了 和 之间的一条伪路径,从而在一个本不存在关联的地方创建了统计关联。我们无意中选择了那个足够幸运以至于与 中随机噪声对齐的 。
嵌套交叉验证是解决方案,因为它打破了这种因果纠缠。超参数 是使用内层循环选择的,但最终性能是在外层测试集上测量的。因为外层测试指标 并未用于选择 ,所以我们没有在涉及它的对撞节点上施加条件。评估是干净的。用因果关系的语言来说,嵌套程序近似于一种干预(intervention),使我们能够估计我们选择的建模策略的真实效果,而不受选择偏差的影响。这是预测建模和因果推理的美丽融合,揭示了寻找诚实性能估计的核心,实际上是寻找一个干净的因果实验。