机器学习 - 交叉验证
交叉验证
在调整模型时,我们的目标是提高模型在未见数据上的整体性能。超参数调整可以使测试集上的性能得到显著提高。然而,针对测试集优化参数会导致信息泄露,从而使模型在未见数据上的表现更差。为了纠正这一点,我们可以执行交叉验证。
为了更好地理解交叉验证(CV),我们将在鸢尾花数据集上执行不同的方法。首先,让我们加载并分离数据。
from sklearn import datasets X, y = datasets.load_iris(return_X_y=True)
交叉验证有很多方法,我们将从 k 折交叉验证开始。
K 折
用于模型训练的数据被分割成 k 个较小的集合,用于验证模型。然后,模型在 k-1 个训练集上进行训练。剩余的折则用作验证集来评估模型。
由于我们将尝试对鸢尾花的不同物种进行分类,我们需要导入一个分类器模型,在本练习中,我们将使用 DecisionTreeClassifier
。我们还需要从 sklearn
导入 CV 模块。
from sklearn.tree import DecisionTreeClassifier from sklearn.model_selection import KFold, cross_val_score
加载数据后,我们现在可以创建并拟合一个模型进行评估。
clf = DecisionTreeClassifier(random_state=42)
现在让我们评估我们的模型,看看它在每个 k 折上的表现如何。
k_folds = KFold(n_splits = 5) scores = cross_val_score(clf, X, y, cv = k_folds)
查看所有折的平均得分也是一个好习惯,以了解 CV 的整体表现。
实例
运行 k 折 CV:
from sklearn import datasets from sklearn.tree import DecisionTreeClassifier from sklearn.model_selection import KFold, cross_val_score X, y = datasets.load_iris(return_X_y=True) clf = DecisionTreeClassifier(random_state=42) k_folds = KFold(n_splits = 5) scores = cross_val_score(clf, X, y, cv = k_folds) print("交叉验证得分:", scores) print("平均 CV 得分:", scores.mean()) print("用于平均的 CV 得分数量:", len(scores))
分层 K 折
在类别不平衡的情况下,我们需要在训练和验证集中考虑这种不平衡。为此,我们可以对目标类别进行分层,这意味着两组都将拥有所有类别的相同比例。
实例
from sklearn import datasets from sklearn.tree import DecisionTreeClassifier from sklearn.model_selection import StratifiedKFold, cross_val_score X, y = datasets.load_iris(return_X_y=True) clf = DecisionTreeClassifier(random_state=42) sk_folds = StratifiedKFold(n_splits = 5) scores = cross_val_score(clf, X, y, cv = sk_folds) print("交叉验证得分:", scores) print("平均 CV 得分:", scores.mean()) print("用于平均的 CV 得分数量:", len(scores))
虽然折的数量相同,但在确保分层类别时,平均 CV 得分从基本的 k 折增加。
留一法(Leave-One-Out, LOO)
与 k 折不同,留一法(LeaveOneOut
)使用 1 个观测值进行验证,并使用 n-1 个观测值进行训练。这种方法是一种详尽无遗的技术。
实例
运行 LOO CV:
from sklearn import datasets from sklearn.tree import DecisionTreeClassifier from sklearn.model_selection import LeaveOneOut, cross_val_score X, y = datasets.load_iris(return_X_y=True) clf = DecisionTreeClassifier(random_state=42) loo = LeaveOneOut() scores = cross_val_score(clf, X, y, cv = loo) print("交叉验证得分:", scores) print("平均 CV 得分:", scores.mean()) print("用于平均的 CV 得分数量:", len(scores))
我们可以观察到,执行的交叉验证得分数量与数据集中的观测值数量相等。在这种情况下,鸢尾花数据集中有 150 个观测值。
平均 CV 得分为 94%。
留 P 法(Leave-P-Out, LPO)
留 P 法有与留一法的一个细微差别,在于我们可以选择在验证集中使用的 p 的数量。
实例
运行 LPO CV:
from sklearn import datasets from sklearn.tree import DecisionTreeClassifier from sklearn.model_selection import LeavePOut, cross_val_score X, y = datasets.load_iris(return_X_y=True) clf = DecisionTreeClassifier(random_state=42) lpo = LeavePOut(p=2) scores = cross_val_score(clf, X, y, cv = lpo) print("交叉验证得分:", scores) print("平均 CV 得分:", scores.mean()) print("用于平均的 CV 得分数量:", len(scores))
正如我们所见,这是一个详尽无遗的方法,即使 p = 2,也计算了比留一法更多的得分,但达到了大致相同的平均 CV 得分。
随机拆分
与 KFold 不同,ShuffleSplit
留出一定百分比的数据,不用于训练或验证集。为此,我们必须决定训练和测试集的大小,以及拆分的数量。
实例
运行随机拆分 CV:
from sklearn import datasets from sklearn.tree import DecisionTreeClassifier from sklearn.model_selection import ShuffleSplit, cross_val_score X, y = datasets.load_iris(return_X_y=True) clf = DecisionTreeClassifier(random_state=42) ss = ShuffleSplit(train_size=0.6, test_size=0.3, n_splits = 5) scores = cross_val_score(clf, X, y, cv = ss) print("交叉验证得分:", scores) print("平均 CV 得分:", scores.mean()) print("用于平均的 CV 得分数量:", len(scores))
结束说明
这些只是可以应用于模型的几种 CV 方法。还有更多交叉验证类,大多数模型都有自己的类。请查看 sklearn
的交叉验证以获取更多 CV 选项。