Sklearn 中的交叉验证

2025年3月17日 | 阅读16分钟

数据科学家在使用机器学习模型时,可以通过交叉验证在两个关键方面受益:它可以帮助最大限度地减少所需数据量,并确保机器学习模型的可靠性。交叉验证以牺牲资源使用为代价来实现这一目标;因此,在决定使用它之前,了解其运作方式至关重要。

在本文中,我们将快速回顾交叉验证的优点,然后我们将通过使用知名的 Python Scikit-learn 包中的各种技术来介绍其应用。

什么是交叉验证?

一个基本错误是训练模型以生成预测函数,然后使用相同的数据测试模型并获得验证分数。一个仅仅重复它刚刚检查过的样本标签的模型会获得完美的分数,但无法预测尚未见过的数据。这种情况被称为过拟合。为了避免这种情况,在进行(监督)机器学习研究时,通常会将给定数据的一部分保留为测试集(X_test,y_test)。由于机器学习有时以业务环境中的实验形式开始,我们应该注意“实验”一词不仅仅指学术应用。

交叉验证如何解决过拟合问题?

在交叉验证期间,我们使用初始训练数据集创建多个微型训练-测试拆分。使用这些拆分来微调我们的模型。例如,对于常见的 K 折交叉验证,我们将数据集分成 K 个子组。然后,在模型成功地在 K-1 个数据集上训练后,剩余的数据集用作测试数据集。通过这种方式,我们可以在新数据集上测试模型。在本教程中,我们将学习七种最流行的交叉验证方法。每种方法的代码示例也包含在内。

scikit-learn 中的训练测试拆分函数可以用于快速生成训练和测试数据集的随机拆分。为了在 iris 数据集上训练一个线性回归模型,我们将首先导入数据集。

代码

输出

(150, 4) (150,)
(90, 4) (90,)
(60, 4) (60,)
0.888564580463006

当比较估计器的各种设置时,仍然存在过拟合测试数据集的可能性。这就是为什么我们可以调整参数直到估计器达到最佳性能。模型可能通过这种方式“泄露”有关测试数据集的信息,并且评估指标可能不再反映泛化性能。我们可以通过将数据集的另一部分保留为“验证集”来解决这个问题:在训练数据集上进行训练,然后在验证数据集上进行评估,当实验似乎成功时,我们可以在测试集上进行最终评估。

数据大小减小

通常,数据被分成三个集合。

训练:用于完善机器学习模型的超参数并训练模型。

测试:用于确保改进后的模型在应用于新数据时表现良好,并且模型能够正确泛化。

验证:我们对完全不可靠的数据执行最后检查,因为在优化时,由于参数的选择,关于测试数据集的一些知识会渗入模型。

由于我们可以使用相同的数据集进行训练和测试,因此在工作流程中添加交叉验证有助于消除对验证数据集的需求。

鲁棒性过程

尽管 sklearn 的训练测试拆分方法使用分层拆分,这确保了目标变量的分布在训练集和测试集中是相同的,但仍然有可能无意中在不准确代表现实世界的一个子集上进行训练。

使用 Sklearn 进行交叉验证的方法

留出交叉验证或训练-测试拆分

这种交叉验证过程随机将整个数据集分成训练数据集和验证数据集。通常,整个数据集的大约 70% 用作训练集,剩余的 30% 用作验证数据集。

这种方法的优点是只需将数据集分成训练集和验证集一次。机器学习模型只需根据训练数据集训练一次,从而实现快速执行。

此方法不适用于不平衡数据集。考虑一个包含类别“0”和“1”的不平衡数据集。假设 80% 的数据属于类别“0”,其余 20% 属于类别“1”,在执行训练-测试拆分后,训练数据集占数据集的 80%,测试数据占 20%。训练数据集可能包含 100% 的类别“0”数据,而测试数据集包含 100% 的类别“1”数据。由于我们的模型以前从未遇到过类别“1”数据,因此它对我们的测试数据不会很好地泛化。

代码

输出

Size of Dataset is: 150
Accuracy score for the training dataset is:  0.9904761904761905
Accuracy score for the testing dataset is:  0.9111111111111111

K 折交叉验证

整个数据集使用 K 折交叉验证过程分成 K 个大小相等的部分。每个分区都称为一个“折叠”。我们称之为 K 折,因为有 K 个部分。其中一个折叠用作验证数据集,而其他 K-1 个折叠用作训练数据集。

此过程重复 K 次,直到每个折叠都被用作验证数据集,其余折叠为训练数据集。

模型最终准确性是根据验证数据集的 k 个模型的平均准确性计算的。

代码

输出

Size of Dataset is: 150
K-fold Cross Validation Scores are:  [1.         1.         0.86666667 0.93333333 0.83333333]
Mean Cross Validation score is:  0.9266666666666665

这种技术不应该用于评估不平衡数据集。正如在留出交叉验证中提到的,训练数据集的所有折叠可能只包含类别“0”的样本,而不包含类别“1”的任何样本。而验证数据集将包含类别“1”的样本。

此外,我们不能将此与时间序列数据一起使用——样本的顺序对于时间序列数据很重要。与此相反,对于 K 折交叉验证,样本是随机选择的。

分层 K 折交叉验证

改进的 K 折交叉验证方法称为分层 K 折,通常应用于不平衡数据集。整个数据集被分成 K 个大小相同的折叠,就像 K 折一样。

然而,在这种方法中,每个折叠将包含与整个数据集相同比例的目标变量出现次数。

此方法对不平衡数据表现良好。在分层交叉验证中,每个折叠将以与整个数据集相同的比例代表所有数据类别。

样本的顺序对于时间序列数据很重要;因此,此方法不适用于时间序列。然而,分层交叉验证以随机顺序选择样本。

代码

输出

Size of Dataset is: 150
Stratified k-fold Cross Validation Scores are:  [0.96666667 1.         0.93333333 0.96666667 1.        ]
Average Cross Validation score is:  0.9733333333333334

留 P 出交叉验证

一种彻底的交叉验证方法称为留 P 出交叉验证,它使用 n-p 个样本进行模型训练,并使用剩余的 p 个样本作为验证数据集。

假设数据集包含 100 个样本。如果我们将 p=10,则每次迭代将使用 10 个数据条目作为验证数据集,其余 90 个样本将构成训练数据集。

此过程重复执行,直到整个数据集已拆分为 n-p 个训练样本数据集和 p 个样本的验证数据集。

每个数据样本都用于训练和验证。

此方法需要较高的计算时间。上述方法将花费更多时间计算,因为它将继续执行,直到所有样本都被用作验证数据集。

这种方法不适用于不平衡数据集。与 K 折交叉验证类似,如果训练数据集只包含一个类别的样本,我们的模型可能无法泛化到验证数据集。

代码

输出

Size of Dataset is:  150
LeavePOut Cross Validation Scores are:  [1. 1. 1. ... 1. 1. 1.]
Average Cross Validation score is:  0.9494854586129754

留一法交叉验证

这种彻底的交叉验证方法,称为“留一法交叉验证”,使用 n-1 个样本作为训练数据集,剩余的 1 个样本点作为验证数据集。

假设数据集包含 100 个样本。然后,每次迭代将使用一个值作为验证数据集,而其余 99 个样本将用作训练数据集。因此,该过程重复执行,直到数据集中的每个样本都已用作验证样本。

当 p=1 时,它等同于留 P 出交叉验证。

代码

输出

Size of Dataset is:  150
LeavePOut Cross Validation Scores are:  [1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1.
 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1.
 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 0. 1.
 1. 1. 1. 1. 1. 0. 1. 1. 1. 1. 1. 0. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1.
 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 0. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 0.
 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 0. 0. 1. 1. 1. 0. 1. 1. 1. 1. 1.
 1. 1. 1. 1. 1. 1.]
Average Cross Validation score is:  0.9466666666666667

蒙特卡洛交叉验证(洗牌拆分)

蒙特卡洛交叉验证是一种非常灵活的交叉验证技术,通常被称为洗牌拆分交叉验证。在这种方法中,数据集被任意分成用于训练和验证模型的子集。

我们已经选择了数据集的多少部分将用作训练数据集,以及哪一部分将用作验证数据集。如果训练数据集和验证数据集大小的总百分比不等于 100,则剩余的数据集不用于训练和验证数据集。

假设我们有 100 个样本,其中 60% 将用作训练数据,20% 将用于验证模型。剩余的 20% (100 - (60 + 20)) 将不被使用。

我们必须指定拆分必须发生多少次。

  1. 用于训练和验证模型的数据集长度由我们决定。
  2. 我们不依赖于循环的拆分数,并且可以选择循环次数。

一个问题是模型可能不会在训练或验证数据集中选择某些样本。

此外,此方法不适用于不平衡数据集。在确定训练数据集和验证数据集的长度之后;所有样本都是随机选择的。因此,训练数据集可能不包含与验证数据集相同类别的数据,从而使模型无法泛化到新数据。

代码

输出

Size of Dataset is:  150
Shuffle Split Cross Validation Scores are:  [0.93333333 0.91111111 0.91111111 0.93333333 1.         0.97777778 0.93333333 0.93333333 0.95555556 0.93333333]
Mean Cross Validation score is:  0.9422222222222223

时间序列交叉验证

什么是时间序列数据?

在一段时间内收集的一系列数据被称为时间序列。由于数据点是在相近的时间间隔内收集的,因此观测值之间存在相关性的可能性。这是时间序列的一个重要特征,将其与标准数据区分开来。

我们已经指出,时间序列数据无法使用早期技术进行分析。因此,我们现在将对时间序列数据进行交叉验证。

时间序列数据的交叉验证

由于我们无法使用未来值来预测过去值,因此我们无法选择时间序列数据的随机样本并将其分配给训练或验证数据集。

我们使用“前向链”方法(也称为滚动交叉验证)根据时间将数据分成训练和验证模型,因为数据的时间顺序对于时间序列相关任务至关重要。

对于训练数据集,我们从数据集的一小部分开始。我们使用该数据集预测后续数据点并验证准确性。

随后的训练数据集然后包含预测值,并预测更多样本。

这是时间序列的最佳方法之一。

其他类型的数据不能使用此方法进行验证。在此策略中,数据集的序列至关重要,但在不同的方法中,算法会为训练或验证数据集选择随机样本。

代码

输出

TimeSeriesSplit(gap=0, max_train_size=None, n_splits=6, test_size=None)
TRAIN: [0 1 2] TEST: [3]
TRAIN: [0 1 2 3] TEST: [4]
TRAIN: [0 1 2 3 4] TEST: [5]
TRAIN: [0 1 2 3 4 5] TEST: [6]
TRAIN: [0 1 2 3 4 5 6] TEST: [7]
TRAIN: [0 1 2 3 4 5 6 7] TEST: [8]
TimeSeriesSplit Cross Validation Scores are:  [0.0, 0.0, 1.0, 0.0, 0.0, 1.0]

交叉验证与训练/测试拆分的比较

测试/训练拆分:使用 70:30、80:20 等比例将输入数据集拆分为训练数据集和测试数据集部分。它的主要缺点之一是它提供了相当大的方差。

训练数据:因变量已知,训练数据集用于训练我们的模型。

测试数据:已训练的模型使用测试数据集进行预测。虽然不是组件,但这与训练数据集具有相似的特征。

通过将数据集拆分为训练/测试拆分集并对结果求平均值,交叉验证数据集用于解决训练/测试拆分的缺点。如果我们希望在模型使用训练数据集训练后提高其性能,则可以使用它。由于每个数据点都用于训练和测试模型,因此它比训练/测试拆分更有效。

交叉验证的局限性

交叉验证方法有一些缺点,其中一些如下所列

它在最佳情况下提供最佳结果。然而,矛盾的数据可能会导致戏剧性的结果。机器学习中数据类型的不确定性是交叉验证的主要缺点之一。

由于预测建模中的数据随时间变化,训练集和验证集之间可能存在差异。例如,如果我们开发了一个股票市场价值预测模型,并且数据集基于过去五年的股票价格进行训练。然而,未来五年可能的股票价格可能大相径庭。在这种情况下,很难预测适当的结果。

交叉验证的应用

  1. 我们可以使用这种方法来评估各种预测建模方法的运作方式。
  2. 它在医学研究方面具有巨大的潜力。
  3. 由于数据科学家已经在医学统计中使用它,我们也可以将其用于荟萃分析。

可视化交叉验证方法

代码

输出

Cross-Validation in Sklearn
Cross-Validation in Sklearn
Cross-Validation in Sklearn
Cross-Validation in Sklearn
Cross-Validation in Sklearn

结论

许多机器学习任务都使用训练-测试拆分的基本思想;但是,如果我们有足够的可用资源,我们应该考虑使用交叉验证来解决我们的问题。许多折叠中不一致的分数将表明我们正在丢失数据中的一个关键关系。这种方法还有助于我们使用更少的数据。