你已经了解到,将数据分成训练集和测试集对于评估模型在新、未见数据上的泛化能力是极其重要的。我们在训练集上训练模型,然后使用测试集来获得对其性能的无偏估计。然而,仅仅依靠一次训练-测试分割本身就可能带来问题。思考我们之前讨论的随机打乱步骤。当你随机划分数据时,仅仅由于偶然性,分配到训练集和测试集的具体数据点就可能明显不同。假设你有一个数据集,并进行80/20的划分。情景1:“幸运”划分: 纯粹偶然地,分配给测试集的20%数据点可能对你的模型来说是特别“容易”预测的例子。或许它们与训练数据的大部分非常相似,或者它们缺少棘手的边界情况。如果发生这种情况,在这个测试集上计算出的评估指标(如准确率、MAE或R平方)会看起来非常出色。你可能会认为你的模型表现极佳。情景2:“不幸运”划分: 反之,随机划分可能将过多最困难或不寻常的数据点放入测试集。这些可能是异常值,或是代表训练数据(80%)中未很好表示的罕见模式的例子。在这种情况下,你的模型很可能在这个特定测试集上表现不佳,即使它已经很好地学会了一般模式。你的评估指标会看起来令人失望,可能导致你放弃一个相当不错的模型。主要问题是变化性。你从单一训练-测试划分中获得的性能估计,可能高度依赖于仅仅由于划分的随机性而进入测试集的具体数据点。你的评估结果可能过于乐观或悲观,这不是因为模型本身的好坏,而是因为选择了用于测试的特定随机样本。digraph G { rankdir=LR; node [shape=box, style=rounded, fontname="sans-serif", margin=0.2]; edge [fontname="sans-serif"]; subgraph cluster_data { label = "原始数据集"; bgcolor="#e9ecef"; D [label="所有数据点"]; } subgraph cluster_split1 { label = "划分1 (幸运吗?)"; bgcolor="#a5d8ff"; Train1 [label="训练集 (80%)\n(多为典型数据)"]; Test1 [label="测试集 (20%)\n(多为“容易”数据)"]; } subgraph cluster_split2 { label = "划分2 (不幸运吗?)"; bgcolor="#ffc9c9"; Train2 [label="训练集 (80%)\n(缺少一些较难数据)"]; Test2 [label="测试集 (20%)\n(包含“困难”数据)"]; } D -> Train1 [label="随机\n划分"]; D -> Test1 [label="随机\n划分"]; D -> Train2 [label="不同\n随机划分"]; D -> Test2 [label="不同\n随机划分"]; Test1 -> Eval1 [label="评估模型", color="#1c7ed6"]; Test2 -> Eval2 [label="评估模型", color="#f03e3e"]; Eval1 [label="高表现\n(可能高估)", shape=ellipse, style=filled, fillcolor="#74c0fc"]; Eval2 [label="低表现\n(可能低估)", shape=ellipse, style=filled, fillcolor="#ffa8a8"]; }同一数据集的不同随机划分可能导致测试集具有不同的特点,从而可能为同一模型带来不同的性能评估。因此,尽管单一的训练-测试划分远好于在训练数据上进行评估,但它不能提供模型真实泛化能力最稳定或最可靠的反映。你获得的性能分数可能无法代表模型在另一个未见数据随机样本上的表现。这种局限性引出了更多的评估技术。如果一次划分可能是幸运或不幸运的,我们是否可以对多次不同划分的结果取平均值呢?这就是交叉验证背后的核心理念,我们将在下一节介绍这项技术。它旨在通过多次重复划分和评估过程,提供更稳定可靠的模型性能估计。