机器学习详解(21):K折交叉验证详解

在训练机器学习模型时,我们常常关心一个问题:模型在未见过的新数据上表现如何?这时,K折交叉验证(K-Fold Cross-Validation)就发挥了作用。它提供了一种评估模型泛化能力的方式,帮助我们避免模型在某一份数据上表现好,而在真实场景中表现不稳定。

1 原理

K折交叉验证是一种将数据集划分为K个子集的策略。模型在K轮中每次使用其中一个子集做验证,其余K-1个子集用于训练。这样每个数据点都至少被验证一次,能有效评估模型在不同数据分布下的表现。

1.1 介绍

K折交叉验证 vs 训练测试划分(Train-Test Split)

传统的训练-测试划分方法将数据划分为两部分,例如80%用于训练,20%用于测试。这种方法虽然简单快捷,但评估结果容易受到划分方式的影响,导致高方差。

在这里插入图片描述

K折交叉验证则能减少这种方差风险,因为它通过多轮验证来更全面地评估模型。下图展示了5折交叉验证的流程:将整个数据集平均划分为5份,每次选取其中一份作为测试集,其余四份作为训练集,重复5轮训练和评估,确保每个子集都被用作一次测试集。最终对5个模型的评估结果取平均,得到更稳定、全面的模型性能估计。

在这里插入图片描述

为什么使用K折交叉验证?

  • 更稳定:不依赖于一次性的数据划分。
  • 更全面:每个样本都参与训练和验证。
  • 更抗过拟合:可发现某一数据划分下的过度拟合问题。

如何选择合适的K?

  • K = 2 K=2 K=2 3 3 3:适合资源有限或快速估计。
  • K = 5 K=5 K=5 10 10 10:实践中最常见的选择,平衡计算成本与评估稳定性。
  • K = 20 K=20 K=20:评估更细致,但计算代价大,若子集太小可能导致高方差。

1.2 其他交叉验证方法

方法名适用场景描述推荐使用情况
标准K折回归 & 分类将数据均分为K份,轮流做测试集适用于样本平衡的数据集
分层K折(Stratified)分类为主每一折中类别分布与整体相同适合类别不均的数据集
留一法(LOOCV)小数据集每次留一个样本测试,剩余训练精度高但计算开销大
留P法(Leave-P-Out)小数据集每次留出P个样本做测试用于分析小样本变动影响
分组K折(Group K-Fold)有分组结构的数据保证同一组不被划分到不同集合数据非独立样本(如用户)
分层分组K折有分组且类别不均保持分组完整且类别比例一致最复杂但最稳定,适用于真实世界复杂数据
方法名适用场景描述(做法 + 原理)推荐使用情况
标准K折(KFold)回归 & 分类将数据随机打乱后平均分为K份,每一份轮流作为测试集,其余作为训练集。**每个样本恰好验证一次、训练K-1次。**适合数据分布均匀的情况。适用于样本量适中、类别分布均衡的场景,如房价预测、图片分类等。
分层K折 (Stratified KFold)分类为主和标准K折类似,但每一折中类别的比例与整个数据集保持一致,比如整体正负样本比例是8:2,那每一折也会尽量接近这个比例。适合类别不平衡的分类任务(如欺诈检测、医疗诊断),否则标准KFold会造成某些折全是某一类。
留一法 (Leave-One-Out, LOOCV)小数据集每次只留一个样本作为测试,其余所有样本用来训练。一共做n次(样本数量为n),结果更稳定但开销大。适合数据很少但要求精度高的情况,比如医学研究中的小样本病人数据。
留P法(Leave-P-Out)小数据集和LOOCV类似,每次留出P个样本做测试,其余做训练。P可以是2、3等。更灵活控制测试集大小,适合观察数据敏感性。主要用于模型鲁棒性分析、小数据实验设计,不常用于大规模评估。
分组K折 (Group KFold)分组结构数据每组数据具有相同特征(如来自同一用户),该方法会确保同一组不会同时出现在训练和测试集中,防止“数据泄漏”。适合有“组”概念的数据(如多条记录属于一个用户),用于推荐系统、个性化模型等。
分层分组K折 (Stratified Group KFold)分组且类别不均结合分层K折和分组K折:**保持每折中类别比例一致,同时同一组数据不被拆分。**这是目前最复杂也最稳定的做法。适用于真实世界复杂数据,如多用户、多类别医疗图像、教育数据,尤其适合深度学习前的数据准备。

不同的交叉验证方法,是为了解决以下几个数据结构问题:

问题类型举例推荐方法
类别不平衡正负样本比例严重失衡StratifiedKFold
数据量很少医疗、金融中仅有几十个样本LOOCV, Leave-P-Out
数据成组一个用户下有多个行为记录GroupKFold
有组也有类别不均多用户 + 多类别的教育/推荐/医疗数据StratifiedGroupKFold

2 K-Fold代码实现

我们将使用 scikit-learn 库中的California Housing数据集,这是基于1990年美国人口普查中加州地区的房屋信息整理而成的。其目标变量MedHouseVal表示各区域的中位数房价,数据集中包含8个特征,分别为地区中位收入、房屋平均年龄、每户平均房间数、每户平均卧室数、总人口数、每户平均居住人数、地区纬度和经度,反映了加州各地的居住和人口特征。

  1. 加载数据集
from sklearn.datasets import fetch_california_housing 
data = fetch_california_housing()
  1. 准备特征与标签
import pandas as pd 
X = pd.DataFrame(data.data, columns=data.feature_names) 
y = data.target
  1. 设置KFold验证器
from sklearn.model_selection import KFold
k = 5 
# 将数据划分为5个折叠
kf = KFold(n_splits=k, shuffle=True, random_state=42)

(1)shuffle=True:在划分之前先对数据进行随机打乱。这一步非常重要,尤其是当数据原本有顺序(比如地理位置、时间序列)时,否则容易导致某一折分布不均。

假设你有一个按收入排序的数据集,样本从低收入到高收入排列:

[,,,,,,,,]

如果你直接将这个数据集分为 3 折:

  • Fold 1:低, 低, 低
  • Fold 2:中, 中, 中
  • Fold 3:高, 高, 高

每一折都只包含一种收入水平,不具备整个数据的代表性。模型在某一折上训练得到的规律,可能在另一折完全无效,导致评估不准确、方差大和结果不稳定

(2)random_state=42:设置随机种子,确保每次运行时划分方式一致,实现结果可复现性。42是一个常见的固定值(可以设为任意整数)。

  1. 初始化模型
from sklearn.linear_model import LinearRegression 
model = LinearRegression()
  1. 执行交叉验证并评估R²得分
from sklearn.model_selection import cross_val_score 
scores = cross_val_score(model, X, y, cv=kf, scoring='r2')

参数设置如下:

参数含义
model你要评估的模型对象,比如 LinearRegression()
X特征变量(DataFrame或NumPy数组)
y目标变量(标签)
cv=kf指定交叉验证的划分方式,这里传入KFold对象kf(即5折)
scoring='r2'指定使用的评分指标,这里是回归任务常用的 R 2 R^2 R2 分数(决定系数)

返回值scores是一个数组,包含每一折交叉验证的评估分数;

  1. 计算平均R²分数
import numpy as np 
average_r2 = np.mean(scores) 
print(f"R² Score for each fold: {[round(score, 4) for score in scores]}")
print(f"Average R² across {k} folds: {average_r2:.2f}")

输出如下:

R² Score for each fold: [np.float64(0.5758), np.float64(0.6137), np.float64(0.6086), np.float64(0.6213), np.float64(0.5875)]
Average R² across 5 folds: 0.60

平均 R 2 R^2 R2分数为0.60,意味着模型能解释数据中约60%的方差。在实际回归任务中,0.60是一个中等偏上的结果,表示模型有一定预测能力,但仍有提升空间。

3 总结

K折交叉验证是一种比传统训练测试划分更稳定、可信的模型评估方法。它可以最大程度降低模型对某一特定划分的依赖,从而提升模型在真实场景下的表现力和稳定性。

### k交叉验证原理与应用 #### 基本理论和步骤 k交叉验证是一种用于评估机器学习模型性能的技术。该技术的核心思想是将原始数据随机划分为k个互斥子集(称为“叠”),每个子集大约占总数据量的1/k[^1]。 对于每一次迭代,选择其中一个子集作为验证集,其余(k-1)个子集组合成训练集。这样可以得到k组不同的训练/测试分割方式,从而使得每一个观测值都有机会被选作验证集中的一员。此过程重复执行k次,每次使用不同部分的数据作为验证集,最终汇总这k轮的结果以获得更稳定可靠的估计[^2]。 #### 应用场景 当面临有限规模的数据集时,采用传统的单一分割可能导致过拟合风险增加或泛化能力不足等问题;而通过引入k交叉验证,则可以在一定程度上缓解这些问题并提高模型评价指标的真实性。此外,在超参数调优过程中也经常运用到这种方法来寻找最优配置方案。 #### 实现方法 下面给出Python环境下基于Scikit-Learn库的一个简单例子: ```python from sklearn.model_selection import cross_val_score, KFold from sklearn.datasets import load_iris from sklearn.linear_model import LogisticRegression # 加载鸢尾花分类数据集 data = load_iris() X, y = data.data, data.target # 定义逻辑回归模型 model = LogisticRegression(max_iter=200) # 创建KFold对象指定分拆策略,默认shuffle=False kf = KFold(n_splits=5) # 使用cross_val_score函数计算平均得分 scores = cross_val_score(model, X, y, cv=kf) print(f'Cross-validation scores: {scores}') print(f'Mean score: {"{:.3f}".format(scores.mean())}') ``` 上述代码展示了如何利用`sklearn`中的工具快速完成一次完整的五交叉验证实验,并输出各轮次的表现分数及其均值。值得注意的是,这里选择了线性支持向量机作为待测算法之一,但在实际操作中可以根据具体需求替换为其他类型的预测器[^3]。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

tilblackout

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值