跳到主要内容

数据划分与泄漏

数据泄漏(Data Leakage)是指训练、特征工程、模型选择或评估环节使用了在真实预测场景中不可得的信息,导致评估结果虚高。

需要厘清两个误区:

  1. 训练准确率高不等于泄漏。
  2. 强相关特征(Proxy)不一定非法。关键在于该信息在预测时刻是否真实存在且被允许使用。

定义信息边界​

在动手切分数据前,必须明确以下元数据:

unit 预测对象(如:患者、订单、设备)
prediction_time 必须做出预测的时间点
horizon 预测目标的时间跨度(如:未来30天)
available_info 预测时刻真实可用且合规的信息集合
label_time 标签生成、成熟及可能修订的时间
split_key 禁止跨集合的实体、群体或时间维度

信息的合法性是相对于部署时的信息集 I(t)\mathcal{I}(t) 而言的。数据库里存在某个字段,不代表它在预测时刻 tt 已经生成,也不代表业务规则允许模型使用它。

泄漏类型与对策​

类型典型场景失真原因控制手段
目标泄漏/结果发生后的信息泄漏用出院后的账单数据预测入院时的风险特征由结果事件产生(因果倒置)审计事件时间戳与数据血缘(Lineage)
时间泄漏随机切分时间序列,或使用了未来的数据修订值训练集看到了“未来”的状态采用前向切分(Forward Split)或数据版本(Vintage)管理
实体/群体泄漏同一患者/设备同时出现在训练集和测试集模型记住了身份或历史模式使用 Group Split,必要时结合 Group + Time
重复/近重复同一图片的不同裁剪、模板化文档跨集合出现测试集并非独立新样本切分前对近重复样本进行聚类或分组
预处理泄漏在全量数据上拟合 Scaler、Imputer、PCA 或特征选择测试集分布影响了变换参数所有变换仅在训练折(Fold)内 Fit,测试集仅 Transform
模型选择泄漏反复根据测试集指标调整模型或阈值测试集变成了隐式的验证集锁定测试集,或获取全新的 Holdout 数据
基准污染训练语料中包含测试题及其答案模型在背诵而非泛化溯源(Provenance)、去重、来源与时间隔离

注意: 部署时合法可用的 Proxy 特征,可能只是捷径、偏见或脆弱的相关性,这属于模型鲁棒性问题,而非严格意义上的泄漏。对此应通过子群体分析、干预测试和分布偏移检测来评估,而不是简单地将所有强相关特征视为泄漏。

切分策略应模拟真实使用场景​

不同的部署问题需要不同的切分逻辑:

部署问题推荐切分方式该切分无法回答的问题
同分布的新独立样本分层随机切分(Stratified Random)时间漂移、同一实体的记忆效应
新患者/用户/设备群体切分(Group Split)未来政策或环境变化
未来时间段时间前向切分(Temporal Forward)新机构或新地区的情况
新机构/地区外部/群体保留(External/Group Holdout)所有未知的外部环境
空间依赖样本空间块切分(Blocked Spatial)未观测区域的任意外推

提示: 分层抽样(Stratification)仅保证标签比例一致,它不能防止同一实体、时间邻近或重复样本跨越训练/测试边界。

测试集始终单独留出;其余训练数据进行五折交叉验证,每轮轮换验证折。查看清晰大图

先看右侧:测试集从一开始就单独留出。左侧每一行用一个蓝色折做验证,其余绿色折用于拟合;预处理也要在每轮的训练折内重新拟合。测试集不参与选模型,只用于最后评估。图中的五折是过程示例,并非所有任务都应这样切分。

Pipeline 不变量​

设训练索引为 ItrI_{tr},验证索引为 IvaI_{va}。任何从数据中学习参数的变换 TηT_\eta 必须满足:

η^=fit⁡(T,DItr),Xva′=Tη^(XIva).\hat\eta=\operatorname{fit}(T,D_{I_{tr}}), \qquad X'_{va}=T_{\hat\eta}(X_{I_{va}}).

这涵盖了标准化、缺失值填充、词表构建、PCA、特征选择、目标编码(Target Encoding)、过采样及学习式数据增强。

  • 交叉验证(CV): 每个 Fold 内部必须重新 Fit 所有变换。
  • 嵌套交叉验证(Nested CV): 外层循环用于评估泛化性能,内层循环用于超参数或特征选择。
  • 常见错误: 先在全量数据上做特征选择,再进行 CV,这依然构成泄漏。

一个只用训练数据拟合的变换​

scikit-learn 泄漏指南遵循同一规则:在训练数据上学习预处理参数,然后原样应用。假设训练特征值为 2 和 4,验证值为 100。训练集均值为 3,所以验证值中心化后为 97。若全局中心化,均值会变成 106/3106/3,验证数据便改变了训练样本的表示。

train = [("A", 2.0), ("B", 4.0)]
valid = [("C", 100.0)]
assert {g for g, _ in train}.isdisjoint(g for g, _ in valid)
center = sum(x for _, x in train) / len(train)
assert [x - center for _, x in train] == [-1.0, 1.0]
assert [x - center for _, x in valid] == [97.0]

这个示例测试新实体。预测已知患者的未来就诊时,可以合法使用当时已有的历史记录;患者不重叠的测试则回答未见患者的问题。若目标是未来的新患者,应先定时间截点,只保留截点之前且标签已成熟的训练记录,再评估之后从未进入训练集的患者。报告因此排除的回访患者,因为这项限制改变了目标人群。

Pipeline 能防止跨折拟合错误,却不能消除训练集内部的所有目标泄漏。目标编码可能把某行自身的标签写入该行特征;训练编码应采用折外计算或合适的时序计算。重采样只作用于训练数据,不要改变验证集和测试集的类别比例。

实战案例:30天再入院风险预测​

场景: 在患者出院时,预测其30天内是否再入院。

错误设计:

  • 随机切分就诊记录,导致同一患者同时出现在训练和测试集。
  • 使用了30天窗口结束后才完整的账单状态作为特征。
  • 在全量数据上计算诊断代码频率以筛选特征。
  • 根据测试集 ROC-AUC 选择模型,再根据测试集召回率调整阈值。

稳健设计:

  1. 冻结信息边界: 明确预测时点及允许使用的字段清单。
  2. 分组与时间切分: 先按患者分组,再按时间将较晚的 Cohort 留出作为测试集。
  3. 训练专用 Pipeline: 仅在训练 Cohort 上拟合缺失值填充、词表和特征选择器。
  4. 验证集调优: 在验证集上选择模型和阈值。
  5. 单次测试: 测试集仅运行一次,并按医院、时间、关键子群体切片报告结果。
  6. 标签成熟度检查: 排除30天观察期未满的样本,避免将其误判为负例。

如果修正泄漏后性能大幅下降,这通常说明旧系统依赖的是身份记忆或未来信息,而非模型本身变差了。

泄漏探针与负对照​

为了主动发现泄漏,建议执行以下检查:

  • 时间审计: 为每个特征记录事件发生时间、入库时间、修订时间。
  • 单特征探针: 单独训练可疑特征,若性能异常高,需追溯其数据血缘。
  • ID 探针: 移除或打乱实体标识符及高基数 Proxy 特征。
  • 重复审计: 检查精确重复及近重复样本。
  • 标签置乱(Permutation): 若完整 Pipeline 在随机打乱标签后仍显著高于随机基线,可能存在 Bug 或泄漏。
  • 边界断言: 代码层面断言同一 Group 不跨集合、训练时间早于测试时间、变换器未在测试集上 Fit。
  • 新鲜 Holdout: 对于被反复查看过的基准测试集,获取全新的保留数据。

局限: 标签置乱无法发现所有泄漏。例如,如果某个特征直接编码了标签信息,且该特征与标签一起被置乱,它们之间的相关性可能依然存在。因此,必须结合数据血缘分析。

概念辨析​

  • 过拟合(Overfitting): 模型学习了训练样本中的噪声,即使 Pipeline 合法也可能发生。
  • 泄漏(Leakage): 开发流程越过了信息边界。
  • 分布偏移(Distribution Shift): 部署时的数据分布与评估时不同。
  • 混杂(Confounding): 共同原因扭曲了因果解释。

这四者可能同时存在。修复泄漏并不保证消除过拟合或分布偏移。

发布前检查清单​

prediction_time: explicit
label_horizon_and_maturity: explicit
unit_and_group_key: explicit
split_algorithm_and_seed: versioned
all_learned_transforms_fit_on_train_only: true
test_used_for_selection: false
duplicate_and_overlap_audit: complete
feature_availability_lineage: reviewed
known_residual_risks: listed

本文聚焦于离线监督学习场景。在线实验、强化学习、联邦学习和持续学习还涉及干预、反馈和策略泄漏等更复杂的问题,需单独设计。

探索关联打开关联网络