跳到内容

4.2 数据切分、交叉验证与泄漏:评估集要模拟模型将面对的未知

模型在随机切分上表现近乎完美。你检查样本后发现,同一任务被日志拆成几十行,训练集和测试集各有一部分;模型只是认出了任务 ID 和固定模式。数据从未真正“未知”。

切分不是固定的 60/20/20 配方。它是一场部署模拟:模型未来要面对新记录、新时间、新队伍还是新站点,决定了隔离单位。

本课目标

  • 给 training、validation/CV 和 test 分配不同职责;
  • 根据独立、分组、时间和空间结构选择切分;
  • 把 preprocessing、feature selection 和 calibration 放入正确边界;
  • 识别反复查看测试集造成的适应性过拟合。

1. 三类数据职责

  • training:拟合模型和预处理参数;
  • validation/CV:选择特征、算法、超参数、阈值和停止点;
  • test:方案冻结后估计整个选择流程的泛化表现。

如果根据 test 结果改变模型、特征或论文叙事,test 已参与选择。需要新 holdout、nested CV 或诚实标注结果偏乐观。

固定百分比不是目标。样本小可用交叉验证,时间变化快可能用多个 rolling windows,测试集还要足够覆盖关键群体与罕见失败。

2. 随机切分的适用条件

随机行切分近似假设样本可交换,且部署目标与当前分布相似。分类可 stratify label 以减少类别比例波动,但:

  • 不保证所有重要交叉群体平衡;
  • 不处理同一实体重复;
  • 不模拟未来漂移;
  • 不能修复选择偏差。

随机种子只保证某次伪随机过程可复现,不证明结果稳健。可重复多次切分报告分布。

3. Group split

同一用户、设备、队伍、病人或文档的多行高度相关,应按泛化目标把完整 group 放在同一 fold。

python
from sklearn.model_selection import GroupKFold

cv = GroupKFold(n_splits=5)
for train_idx, valid_idx in cv.split(X, y, groups=team_id):
    assert set(team_id[train_idx]).isdisjoint(team_id[valid_idx])

若一人属于多个家庭/站点,group 定义可能重叠,需要连接分量或更高层隔离。只按单个字段 group 可能仍有泄漏。

4. 时间切分

预测未来时,训练应早于验证。Rolling/expanding window 可评估多个时期:

text
train Jan–Mar → validate Apr
train Jan–Apr → validate May
train Jan–May → validate Jun

还要设置:

  • label maturation:训练样本标签已完整观察;
  • feature/label gap:防止重叠窗口泄漏;
  • embargo:金融等重叠事件场景隔离邻近期;
  • late-arriving data:历史回放只使用当时可用版本。

简单按时间排序后切最后 20%,仍可能把同一事件的未来修订泄漏进训练特征。

5. 空间与站点泛化

如果模型要部署到未见堡垒,测试应留出整个堡垒;若只在已有堡垒预测未来,则可在每个堡垒内按时间切。两种问题不同,应分别评估。

地理邻近会造成空间相关。留出相邻网格的随机点可能过于容易,可采用区域 block 和缓冲带。

6. Preprocessing 必须在 fold 内 fit

会从数据学习参数的步骤都属于模型选择过程:

  • imputation、scaling、encoding;
  • feature selection、PCA;
  • target encoding;
  • resampling/SMOTE;
  • calibration 和 threshold selection。
python
from sklearn.pipeline import Pipeline
from sklearn.impute import SimpleImputer
from sklearn.preprocessing import StandardScaler
from sklearn.linear_model import LogisticRegression

pipeline = Pipeline([
    ("impute", SimpleImputer(strategy="median")),
    ("scale", StandardScaler()),
    ("model", LogisticRegression(max_iter=1000)),
])

交叉验证 pipeline,每折会重新 fit 前处理。先对全表标准化/筛选再 CV,即使没直接看 label,也让验证折影响转换;目标编码和监督选择泄漏更严重。

7. 重采样只能在训练折

对少数类 oversampling、undersampling 或 synthetic sampling 应在每个训练 fold 内做。先 SMOTE 再切分会让一个原样本及其合成邻居跨 fold,显著乐观。

评估集应保留部署时自然分布。若业务会改变采样/筛选,还需用权重或单独目标分布评估。

8. Nested cross-validation

同一组 CV folds 既选超参数又报告最佳分数,会产生选择乐观。Nested CV:

  • inner loop 选择 pipeline 和超参数;
  • outer loop 评估整个选择过程。

成本较高,但小数据、候选多且需要可靠比较时很重要。最终模型可在全部开发数据上按选定流程重训,独立 test 仍只使用一次。

9. 数据去重不能跨越 test 边界偷看

先对全数据做近重复检测可能利用 test 内容来修改 training。正确流程取决于目标:

  • 全局来源层去除真正重复采集,可在切分前,规则与原因要固定;
  • 语义近重复/相似图像应先分 group,再按 group 切;
  • 根据 test 表现发现并删除“麻烦样本”属于污染。

版本、哈希、来源 ID 和去重簇应保留以审计。

10. Test set 的操作纪律

text
访问者与用途受限
评估脚本和主指标预先冻结
只返回必要聚合,避免逐样本反复调试
每次访问记录模型、数据和理由
测试后变更必须重新建立评估边界
测试分布与部署变化时重新取样

测试集不是永恒标准。随着团队反复公开 benchmark 成绩,组织知识也会对它过拟合。

常见误区

  • 拆成三份就没有泄漏:切分单位和所有 fit 步骤同样重要。
  • stratify 解决分布问题:它只约束指定标签比例。
  • 随机种子固定就可靠:可能只是复现一次偶然切分。
  • test 只看不训练所以可多看:人的选择也会过拟合。

练习

  1. 对重复任务日志比较行随机和 GroupKFold 分数。
  2. 为 30 天 label window 设计时间 split 与 gap。
  3. 演示全数据 feature selection 与 fold 内选择的差异。
  4. 为测试集建立访问日志和“何时需要新 test”规则。

小结

评估可信度来自隔离真实未知,而不是文件名叫 test.csv。时间、实体、空间和所有数据学习步骤都要与部署目标一致。

下一课用学习曲线和误差分解诊断欠拟合、过拟合与分布变化,并选择对症控制。

Built with VitePress | Software Systems Atlas