【精选优质专栏推荐】


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

在这里插入图片描述

前言

许多初学者最初会依赖训练-测试(train-test)方法来评估模型。该方法直观易用,似乎可以清楚地反映模型在未见数据上的表现。然而,这种方法往往会导致对模型能力的理解不完整。

在本文中,我们将讨论为什么需要超越基本的训练-测试划分,以及交叉验证(cross-validation)如何提供更全面的模型性能评估。我们将引导你完成关键步骤,以实现对机器学习模型更深刻、更准确的评估。

模型评估:训练-测试法与交叉验证

机器学习模型的表现取决于其设计(如线性模型与非线性模型)及参数(如线性回归中的系数)。在考虑如何拟合模型之前,需要确保模型适合数据。

模型性能通常通过其在未见过的数据(或测试数据)上的表现来衡量。在标准训练-测试划分中,我们将数据集分为两部分:一大部分用于训练模型,一小部分用于测试性能。如果测试结果令人满意,则模型被认为适合数据。这种方法简单明了,但并不总是最有效地利用数据。

在这里插入图片描述

然而,通过交叉验证,我们可以更进一步。下图展示了 5 折交叉验证(5-Fold Cross-Validation):数据集被划分为五个“折”。在每一轮验证中,不同的折用作测试集,其余折组成训练集。这个过程重复五次,确保每个数据点都被用于训练和测试。

在这里插入图片描述

下面通过示例来说明上述内容:

# 加载 Ames 数据集
import pandas as pd
Ames = pd.read_csv('Ames.csv')

# 导入线性回归、训练-测试划分及交叉验证方法
from sklearn.linear_model import LinearRegression
from sklearn.model_selection import train_test_split, cross_val_score

# 选择特征和目标
X = Ames[['GrLivArea']]  # 特征:GrLivArea,二维矩阵
y = Ames['SalePrice']    # 目标:SalePrice,一维向量

# 将数据分为训练集和测试集
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)

# 使用训练-测试方法的线性回归模型
model = LinearRegression()
model.fit(X_train, y_train)
train_test_score = round(model.score(X_test, y_test), 4)
print(f"Train-Test R^2 Score: {train_test_score}")

# 进行 5 折交叉验证
cv_scores = cross_val_score(model, X, y, cv=5)
cv_scores_rounded = [round(score, 4) for score in cv_scores]
print(f"Cross-Validation R^2 Scores: {cv_scores_rounded}")

训练-测试方法只给出一个 R² 分数,而交叉验证提供了五个不同折的 R² 分数,从而更全面地评估模型性能:

Train-Test R^2 Score: 0.4789
Cross-Validation R^2 Scores: [0.4884, 0.5412, 0.5214, 0.5454, 0.4673]

五个折的 R² 分数大致相等,说明模型稳定。接下来可以判断该模型(如线性回归)是否具备可接受的预测能力。

交叉验证的意义

理解模型在不同数据子集上的表现差异对于机器学习至关重要。训练-测试划分虽有用,但只提供了模型在某一个未见数据集上的表现快照。

交叉验证通过系统地使用多折数据进行训练和测试,提供更稳健、全面的模型评估。每一折都作为独立测试,为模型在不同数据样本上的表现提供洞察。这种多样性不仅帮助识别潜在过拟合,还能确保性能指标(如 R² 分数)更可靠,而非过于乐观或悲观,更准确地反映模型在未见数据上的泛化能力。

下面用可视化展示训练-测试划分与 5 折交叉验证的 R² 分数差异:

# 导入 Seaborn 和 Matplotlib
import seaborn as sns
import matplotlib.pyplot as plt

# 假设 cv_scores_rounded 包含交叉验证分数
# train_test_score 是单一训练-测试 R² 分数

# 绘制交叉验证分数的箱线图
cv_scores_df = pd.DataFrame(cv_scores_rounded, columns=['Cross-Validation Scores'])
sns.boxplot(data=cv_scores_df, y='Cross-Validation Scores', width=0.3, color='lightblue', fliersize=0)

# 将单个分数叠加为点
plt.scatter([0] * len(cv_scores_rounded), cv_scores_rounded, color='blue', label='Cross-Validation Scores')
plt.scatter(0, train_test_score, color='red', zorder=5, label='Train-Test Score')

# 可视化展示
plt.title('模型评估:交叉验证 vs 训练-测试')
plt.ylabel('R^2 Score')
plt.xticks([0], ['Evaluation Scores'])
plt.legend(loc='lower left', bbox_to_anchor=(0, +0.1))
plt.show()

此可视化强调了单一训练-测试评估与交叉验证提供的更广泛洞察之间的差异。

在这里插入图片描述

通过交叉验证,我们能够更深入地理解模型的性能,从而更接近构建既高效又可靠的机器学习解决方案。

使用 K 折交叉验证进行深入分析

交叉验证是可靠机器学习模型评估的基石,其中 cross_val_score() 提供了快速自动化的实现方式。

现在,我们重点介绍 scikit-learn 的 KFold 类,它可以让我们更深入地观察交叉验证的折。KFold 不仅提供评分,还展示了模型在不同数据段上的表现。以下示例复现了前面的案例:

# 导入 KFold 和必要库
from sklearn.model_selection import KFold
from sklearn.linear_model import LinearRegression
from sklearn.metrics import r2_score

# 选择特征和目标
X = Ames[['GrLivArea']].values  # 转为 numpy 数组以适配 KFold
y = Ames['SalePrice'].values    # 转为 numpy 数组以适配 KFold

# 初始化线性回归模型和 K-Fold
model = LinearRegression()
kf = KFold(n_splits=5)

# 手动进行 K 折交叉验证
for fold, (train_index, test_index) in enumerate(kf.split(X), start=1):
    # 划分训练集和测试集
    X_train, X_test = X[train_index], X[test_index]
    y_train, y_test = y[train_index], y[test_index]

    # 拟合模型并预测
    model.fit(X_train, y_train)
    y_pred = model.predict(X_test)

    # 输出当前折的 R² 分数
    print(f"Fold {fold}:")
    print(f"TRAIN set size: {len(train_index)}")
    print(f"TEST set size: {len(test_index)}")
    print(f"R^2 score: {round(r2_score(y_test, y_pred), 4)}\n")

输出示例:

Fold 1:
TRAIN set size: 2063
TEST set size: 516
R^2 score: 0.4884

Fold 2:
TRAIN set size: 2063
TEST set size: 516
R^2 score: 0.5412

Fold 3:
TRAIN set size: 2063
TEST set size: 516
R^2 score: 0.5214

Fold 4:
TRAIN set size: 2063
TEST set size: 516
R^2 score: 0.5454

Fold 5:
TRAIN set size: 2064
TEST set size: 515
R^2 score: 0.4673

KFold 的优势在于其透明性和对交叉验证过程的控制。虽然 cross_val_score() 一行即可完成,但 KFold 允许我们查看数据的具体划分,这在以下情况下非常有用:

  • 了解数据是如何被划分的
  • 在每个折前执行自定义预处理
  • 获取模型性能一致性的洞察

使用 KFold 可以手动迭代每个划分并应用训练和测试流程。这不仅确保了对每阶段使用的数据有清晰了解,还可以根据复杂需求调整流程。

总结

本文探讨了通过交叉验证和 KFold 方法进行彻底模型评估的重要性。两种方法都严格区分训练数据与测试数据,避免数据泄露,从而保证模型性能的准确测量。

此外,每个数据点恰好被验证一次,并在 K-1 折中用于训练,这种方式提供了模型泛化能力的详细视图,提高了其在实际场景中的可靠性。

通过实际示例,我们展示了将这些策略整合到评估流程中,可以构建更可靠、更稳健的机器学习模型,为应对新数据和未见数据的挑战做好准备。

Logo

DAMO开发者矩阵,由阿里巴巴达摩院和中国互联网协会联合发起,致力于探讨最前沿的技术趋势与应用成果,搭建高质量的交流与分享平台,推动技术创新与产业应用链接,围绕“人工智能与新型计算”构建开放共享的开发者生态。

更多推荐