Skip to content

终于把机器学习中的交叉验证搞懂了

发表: at 12:00

今天给大家分享机器学习中的一个关键概念,交叉验证。交叉验证(Cross Validation)是一种用于评估机器学习模型性能的技术,主要用于避免过拟合并提高模型的泛化能力。

它通过将数据集划分为多个子集,并在不同的子集上训练和测试模型,以确保模型能够在新的、未见过的数据上表现良好。

交叉验证的原理

交叉验证的核心思想是:将原始数据集划分成若干个子集,然后使用这些子集对模型进行多次训练和测试。这样可以确保每个数据点都被用于训练和测试,从而减少由于数据划分偏差带来的误差。

  1. 数据划分

    将数据集划分成多个互不重叠的子集(或者称为折)。

  2. 训练与验证

    在每次训练中,选择其中一部分数据作为训练集,剩余部分作为验证集(测试集)。

  3. 评估性能

    通过多次迭代训练和测试,计算模型的平均性能,以获得更稳定的评估结果。

常见的交叉验证技术

常见的交叉验证技术包括 K 折交叉验证、留一法交叉验证、分层 K 折交叉验证、时间序列交叉验证等。

一、K 折交叉验证

K 折交叉验证是最常用的一种交叉验证技术,它将数据集随机划分为 K 个大小相等的子集(折)。每个子集依次作为验证集,其余的 K-1 个子集作为训练集来训练模型。这个过程会重复 K 次,确保每个子集都被用作一次验证集。最终的评估结果是这 K 次验证结果的平均值。

图片

步骤

  1. 将数据集 D 划分成 K 个子集 D1、D2、D3…DK。
  2. 对每个 k 从 1 到 K,用 D - Dk(即去除Dk的数据)训练模型,并用 Dk 验证模型。
  3. 计算每次验证的评估指标(如准确率、均方误差等)。
  4. 计算所有 K 次验证结果的平均值作为最终评估。

优缺点

优点

缺点

from sklearn.model_selection import KFold, cross_val_score
from sklearn.datasets import load_iris
from sklearn.linear_model import LogisticRegression
import numpy as np

# 加载数据集
iris = load_iris()
X, y = iris.data, iris.target

# 定义k折交叉验证
k = 5
kf = KFold(n_splits=k, shuffle=True, random_state=42)

# 定义模型
model = LogisticRegression(max_iter=200)

# 计算交叉验证得分
scores = cross_val_score(model, X, y, cv=kf)

# 输出交叉验证得分
print(f"K-Fold Cross Validation Scores: {scores}")
print(f"Mean Score: {np.mean(scores)}")

二、留一交叉验证 (LOOCV)

留一交叉验证是 K 折交叉验证的特殊形式,其中 K = n,即每次只用一个样本作为验证集,剩余的n-1个样本作为训练集。

这种方法特别适合数据量较小的情形。

图片

步骤

  1. 对于每一个数据点 xi,将其作为验证集,其余的n-1个样本作为训练集。
  2. 在训练集上训练模型,并在验证集 xi 上进行评估。
  3. 重复这个过程 n 次,确保每个样本都被用作验证集一次。
  4. 计算所有验证结果的平均值作为最终评估。

优缺点

优点

缺点

from sklearn.model_selection import LeaveOneOut

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

print(f"LOOCV Mean Score: {np.mean(scores)}")

三、留 P 交叉验证 (LPOCV)

留 P 交叉验证是 LOOCV 的一个扩展,其中在每次迭代中,从数据集中选择 P 个样本作为验证集,剩下的 n - P 个样本作为训练集。

步骤

  1. 从数据集中随机选择 P 个样本作为验证集。
  2. 使用其余的 n - P 个样本作为训练集来训练模型。
  3. 对于每一个验证集,计算评估指标。
  4. 计算所有 n/p 次验证结果的平均值作为最终评估。

优缺点

优点

缺点

四、分层 K 折交叉验证

分层 K 折交叉验证是一种改进的 K 折交叉验证方法,特别适用于类别不平衡的数据集。

在分类任务中,如果数据集中某些类别的样本数较少,K折交叉验证可能导致验证集中某些类别的样本过少,从而影响评估的准确性。

图片

分层K折交叉验证通过确保每个折中各个类别的比例与整个数据集中的比例一致,从而使每个折中的类别分布更加均衡。

步骤:

  1. 将数据集按照类别标签进行分层,确保每个类别的比例在各个折中保持一致。
  2. 然后进行与普通 K 折交叉验证相同的过程。

优缺点

优点

缺点

from sklearn.model_selection import StratifiedKFold

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

print(f"Stratified K-Fold Mean Score: {np.mean(scores)}")

五、时间序列交叉验证

时间序列交叉验证是一种特殊的交叉验证方法,适用于时间序列数据。

在时间序列数据中,数据点之间具有时间上的依赖关系,因此不能像其他交叉验证方法那样随意打乱数据。

常用的方法包括

图片

图片

优缺点

优点

缺点

import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
from sklearn.model_selection import TimeSeriesSplit
from sklearn.linear_model import LinearRegression
from sklearn.metrics import mean_absolute_error

# 生成示例时间序列数据
np.random.seed(42)
n = 100
time_series_data = pd.DataFrame({
    'timestamp': pd.date_range(start='2020-01-01', periods=n, freq='D'),
    'feature': np.arange(n) + np.random.normal(0, 5, n),  # 递增趋势 + 噪声
    'target': np.arange(n) + np.random.normal(0, 3, n)  # 目标变量
})

# 定义特征和目标变量
X = time_series_data[['feature']].values
y = time_series_data['target'].values

# 定义时间序列交叉验证
tscv = TimeSeriesSplit(n_splits=5)

# 存储结果
mae_scores = []

# 执行交叉验证
for train_index, test_index in tscv.split(X):
    X_train, X_test = X[train_index], X[test_index]
    y_train, y_test = y[train_index], y[test_index]
    
    model = LinearRegression()
    model.fit(X_train, y_train)
    y_pred = model.predict(X_test)
    
    mae = mean_absolute_error(y_test, y_pred)
    mae_scores.append(mae)
    print(f"Train size: {len(train_index)}, Test size: {len(test_index)}, MAE: {mae:.4f}")

print(f"Mean MAE: {np.mean(mae_scores):.4f}")

文章来源:微信公众号-程序员学长,原始发表时间:2025年03月11日。


上篇文章
一文搞懂前向传播和反向传播(PyTorch)
下篇文章
解决 Git Push 被拒绝(non-fast-forward)的错误