交叉验证
K 折让每条训练部分样本轮流验证,报告平均分和折间波动,并保留最终测试集。
学习前需要掌握
背景与问题
一次随机划分可能碰巧包含容易或困难样本,导致对模型的判断不稳定。交叉验证在开发数据内轮流留出不同部分,让我们观察同一训练流程在多个验证子集上的表现。
它评估的是给定训练与划分流程,不会自动解决泄漏,也不会因为用了多个折就消除模型选择带来的偏差。
概念定义
第 k 折用其余 K-1 折训练,本折验证;交叉验证用于模型选择,不替代最终测试。
直观理解
进行多轮模拟考试,而不是只凭一次成绩。
核心原理
K 折把开发集划成 K 个验证子集。每轮从其余部分重新拟合模型,再预测当前验证折;每个样本在标准 K 折中恰好验证一次,模型也会被重新训练 K 次。
预处理必须一起重新拟合。填补、缩放与特征选择应在当前训练折中学习,验证折只应用对应变换;通过 Pipeline 包装能让这些边界随每轮训练保持一致。
分层、群组和时间划分对应不同的数据结构。选择划分器之前,应明确要推广到新行、新实体还是未来时间;普通随机 K 折不适合所有情境。
每折分数可以汇总均值与波动,但各训练折共享数据,折分数不是相互独立的重复实验。CV 也不负责把最终模型自动交付:模型选择后通常在完整开发集上另行拟合,再用保留测试集做最终评价。
数学表达
核心表达
划分器必须匹配分类、群组和时间结构;所有预处理都在当前训练折内 fit。
变量含义
变量定义与本页概念定义一致,代码中的同名变量保持相同语义。
计算步骤
- 1保留测试集
- 2选择划分器
- 3固定折
- 4折内 Pipeline fit
代码对应位置
示例 1完整 Pipeline 的 3 折分数与拟合状态:固定 Iris、划分与随机种子复核开发分数;示例没有独立最终测试,不声称上线效果。
案例:150 行开发数据做 3 折验证
用内置 Iris 的 150 行演示 3 折分层验证,每轮训练 100 行、验证 50 行。标准化与逻辑回归一起在训练折拟合,输出 3 个验证分数,而不是一份模型对训练数据的分数。
下方还检查传入的原始估计器没有在原地被拟合。交叉验证使用副本完成各折;若要部署,需要在固定方案后显式 fit 最终流程。这里没有单独测试集,输出仅是教学数据上的开发分数。
计算与实现步骤
- 保留测试集
- 选择划分器
- 固定折
- 折内 Pipeline fit
- 收集每折指标
- 报告均值/标准差
代码实现
示例 1
完整 Pipeline 的 3 折分数与拟合状态
example_01.py用途:固定 Iris、划分与随机种子复核开发分数;示例没有独立最终测试,不声称上线效果。
from sklearn.datasets import load_iris
from sklearn.linear_model import LogisticRegression
from sklearn.model_selection import StratifiedKFold, cross_validate
from sklearn.pipeline import make_pipeline
from sklearn.preprocessing import StandardScaler
X, y = load_iris(return_X_y=True)
model = make_pipeline(StandardScaler(), LogisticRegression(max_iter=1000))
cv = StratifiedKFold(3, shuffle=True, random_state=42)
result = cross_validate(model, X, y, cv=cv, scoring="accuracy")
print("fold_accuracy:", result["test_score"].round(3).tolist())
print(f"mean={result['test_score'].mean():.3f}")
print("original_model_fitted:", hasattr(model.named_steps["logisticregression"], "classes_"))代码解析
解析始终位于完整代码下方,并按实际代码段逐项对应。
输入数据与任务
固定 Iris、划分与随机种子复核开发分数;示例没有独立最终测试,不声称上线效果。
X- 完整特征矩阵,每行一个样本、每列一个特征。
y- 目标标签或连续目标值。
model- 组合预处理和估计器的模型对象。
mean- 训练特征逐列均值。
Step 1 · 1–5 行
导入当前步骤需要的数值计算、预处理、模型或评价工具。依赖集中写在代码开头,便于复现。
from sklearn.datasets import load_iris
from sklearn.linear_model import LogisticRegression
from sklearn.model_selection import StratifiedKFold, cross_validate
from sklearn.pipeline import make_pipeline
from sklearn.preprocessing import StandardScalerStep 2 · 7–13 行
只从训练数据逐列计算均值与标准差,对应标准化公式中的 μ 和 σ。
X, y = load_iris(return_X_y=True)
model = make_pipeline(StandardScaler(), LogisticRegression(max_iter=1000))
cv = StratifiedKFold(3, shuffle=True, random_state=42)
result = cross_validate(model, X, y, cv=cv, scoring="accuracy")
print("fold_accuracy:", result["test_score"].round(3).tolist())
print(f"mean={result['test_score'].mean():.3f}")
print("original_model_fitted:", hasattr(model.named_steps["logisticregression"], "classes_"))代码与数学原理
减去训练均值并除以训练标准差,对应代码中的 mean/std 或 StandardScaler。
预期输出或运行结果
本地 scikit-learn 1.8.0 的核对输出: fold_accuracy: [1.0, 0.92, 0.94] mean=0.953 original_model_fitted: False
常见错误 · 4 条
- 不要在测试集上调用 fit 或 fit_transform;测试集只能复用训练参数。
- CV 前就对全数据拟合预处理,或只报告最好的一折。
- 把折间标准差当作独立样本标准误,或用 CV 代替所有最终测试。
- 以为 cross_validate 已经把原始 estimator 拟合成可部署模型。
实际应用
- 模型比较
- 超参数选择
常见错误
- CV 前就对全数据拟合预处理,或只报告最好的一折。
- 把折间标准差当作独立样本标准误,或用 CV 代替所有最终测试。
- 以为 cross_validate 已经把原始 estimator 拟合成可部署模型。
推荐学习资料
参考库不会生成虚假资源或无效外部链接。