【精选优质专栏推荐】


每个专栏均配有案例与图文讲解,循序渐进,适合新手与进阶学习者,欢迎订阅。

在这里插入图片描述

引言

在验证机器学习模型时,需要在未见过的数据上进行严格测试,以确保其性能评估的稳健性和无偏性。其中最成熟的验证方法之一是交叉验证(cross-validation),它将数据集划分为若干个子集(称为折叠 folds),并在其中一部分上进行训练,同时在剩余部分上进行测试,迭代进行。

虽然 scikit-learn 提供了标准组件和函数来执行传统方式的交叉验证,但仍有一些额外技巧可以让整个过程更高效、更有洞察力或更具灵活性。

本文将介绍其中的七个技巧,并配合代码示例进行实现说明。下文中的示例均基于 scikit-learn 库,因此请确保已正确导入。

建议先熟悉交叉验证的基础知识,可以参考这篇文章作为入门。同时,作为快速回顾,以下是一个在 scikit-learn 中实现的基础交叉验证(尚未使用任何技巧!):

from sklearn.datasets import load_iris
from sklearn.model_selection import cross_val_score
from sklearn.linear_model import LogisticRegression

X, y = load_iris(return_X_y=True)

model = LogisticRegression(max_iter=200)

# 基础的交叉验证策略,k=5 折
scores = cross_val_score(model, X, y, cv=5)

# 输出交叉验证结果:每次迭代的分数 + 平均分
print("Cross-validation scores:", scores)
print("Mean score:", scores.mean())

以下示例默认已经导入了诸如 cross_val_score 之类的基础库和函数。

1. 分层交叉验证 —— 适用于类别不平衡的分类任务

在分类任务中,如果数据集存在类别分布不均衡的问题,普通的交叉验证可能无法保证每个折叠(fold)中的类别比例与整体数据一致。这会导致某些折叠缺乏少数类样本,从而影响模型评估的公正性。

分层 k 折交叉验证(Stratified k-fold)通过在每个折叠中保持类别分布与整体一致,有效解决了这一问题。其实现方式如下:

from sklearn.model_selection import cross_val_score, StratifiedKFold

cv = StratifiedKFold(n_splits=5)
scores = cross_val_score(model, X, y, cv=cv)

这种方法在处理医疗诊断、欺诈检测等类别极不平衡的任务时尤其有用。


2. 打乱数据的 K 折交叉验证 —— 提升分割的鲁棒性

如果数据集中样本存在某种顺序(如按时间排列或按类别分组),直接使用普通的 k 折交叉验证可能会引入偏差。

通过在 KFold 中加入 shuffle=True 参数,可以在划分前打乱数据,从而获得更具代表性和鲁棒性的训练-测试拆分。

from sklearn.model_selection import KFold

cv = KFold(n_splits=5, shuffle=True, random_state=42)
scores = cross_val_score(model, X, y, cv=cv)

这种方法能有效避免“数据顺序偏差”,例如:时间序列按月份排序、用户行为按群组排列等情况。


3. 并行化交叉验证 —— 提升计算效率

在数据量较大时,交叉验证的训练过程会非常耗时。Scikit-learn 提供了并行计算的支持,只需在 cross_val_score 中设置 n_jobs=-1,即可利用所有 CPU 核心同时运行不同折叠的训练过程。

scores = cross_val_score(model, X, y, cv=5, n_jobs=-1)

在实际工程中,这一技巧可以显著缩短模型验证的时间,尤其适用于深度学习之前的特征工程模型、大规模数据集或多次调参实验。


4. 交叉验证预测 —— 获取实例级预测结果

默认情况下,交叉验证只返回每个折叠的分数,然后取平均值作为整体性能指标。如果需要获得每个样本的预测结果(而非仅仅是分数),可以使用 cross_val_predict 替代 cross_val_score

from sklearn.model_selection import cross_val_predict

y_pred = cross_val_predict(model, X, y, cv=5)

这样我们就能基于交叉验证的预测结果进一步构建混淆矩阵(confusion matrix)、ROC 曲线、精确率-召回率曲线等指标,为模型评估提供更细粒度的信息。


5. 超越准确率:自定义评估指标

在很多应用场景中,准确率(accuracy)并不是最合适的评估指标。比如在类别不平衡任务中,召回率(recall)、F1 值(F1-score)往往比准确率更具参考价值。

Scikit-learn 提供了 make_scorer 方法,可以将自定义的评估指标引入交叉验证。

from sklearn.metrics import make_scorer, f1_score, recall_score

f1 = make_scorer(f1_score, average="macro")  # 也可以使用 recall_score
scores = cross_val_score(model, X, y, cv=5, scoring=f1)

通过这种方式,可以根据具体任务选择最合适的性能度量标准,确保评估结果符合业务目标。


6. 留一交叉验证 —— 小数据集的极致评估

留一交叉验证是 k 折交叉验证的极端形式:每次仅留出一个样本作为测试集,其余样本作为训练集,重复至所有样本都被测试一次。

from sklearn.model_selection import LeaveOneOut

cv = LeaveOneOut()
scores = cross_val_score(model, X, y, cv=cv)

这种方法能够最大限度地利用有限的数据,非常适合小规模数据集(如 Iris 数据集)或简单模型的评估。但在大规模数据或复杂模型(如集成学习)中,由于计算代价过高,一般不推荐使用。此方法也可结合前面提到的并行化技巧进一步加速。


7. 管道中的交叉验证 —— 避免数据泄漏

最后一个技巧是将交叉验证应用于包含预处理步骤的机器学习管道(Pipeline)。例如,特征缩放(scaling)必须在交叉验证的每个训练集上单独计算,否则会导致“数据泄漏”。

通过 make_pipeline 可以将预处理与模型训练步骤整合,并在交叉验证中使用:

from sklearn.pipeline import make_pipeline
from sklearn.preprocessing import StandardScaler

pipeline = make_pipeline(StandardScaler(), LogisticRegression(max_iter=200))
scores = cross_val_score(pipeline, X, y, cv=5)

这种方式确保了在每次折叠中,标准化步骤仅基于训练集进行,从而避免信息泄露到测试集,保证评估结果的真实性。


总结

本文介绍了 七个基于 Scikit-learn 的交叉验证优化技巧,它们能够根据不同场景和需求提升验证过程的可靠性和效率。

技巧 说明
分层交叉验证 保持类别比例一致,适用于不平衡分类任务
打乱数据的 K 折 避免顺序或分组带来的偏差,提高鲁棒性
并行化交叉验证 利用全部 CPU 核心加速计算
交叉验证预测 返回样本级预测结果,支持混淆矩阵、ROC 等更深入分析
自定义评估指标 使用 F1、召回率等更符合任务需求的度量方式
留一交叉验证 适用于小数据集和简单模型的极致评估
管道中的交叉验证 将预处理与模型训练整合,防止数据泄漏

通过灵活应用这些技巧,交叉验证不仅能用于性能评估,还能成为模型调优和可靠性验证的重要工具。

Logo

码道开发者社区,聚焦华为云码道 CodeArts 代码智能体,沉淀 Agent、Skill、鸿蒙开发实战内容,供开发者查阅资料、交流技术、分享工程实践

更多推荐