数据划分与泄漏
数据泄漏(Data Leakage)是指训练、特征工程、模型选择或评估环节使用了在真实预测场景中不可得的信息,导致评估结果虚高。
需要厘清两个误区:
- 训练准确率高不等于泄漏。
- 强相关特征(Proxy)不一定非法。关键在于该信息在预测时刻是否真实存在且被允许使用。
定义信息边界
在动手切分数据前,必须明确以下元数据:
unit 预测对象(如:患者、订单、设备)
prediction_time 必须做出预测的时间点
horizon 预测目标的时间跨度(如:未来30天)
available_info 预测时刻真实可用且合规的信息集合
label_time 标签生成、成熟及可能修订的时间
split_key 禁止跨集合的实体、群体或时间维度
信息的合法性是相对于部署时的信息集 而言的。数据库里存在某个字段,不代表它在预测时刻 已经生成,也不代表业务规则允许模型使用它。
泄漏类型与对策
注意: 部署时合法可用的 Proxy 特征,可能只是捷径、偏见或脆弱的相关性,这属于模型鲁棒性问题,而非严格意义上的泄漏。对此应通过子群体分析、干预测试和分布偏移检测来评估,而不是简单地将所有强相关特征视为泄漏。
切分策略应模拟真实使用场景
不同的部署问题需要不同的切分逻辑:
提示: 分层抽样(Stratification)仅保证标签比例一致,它不能防止同一实体、时间邻近或重复样本跨越训练/测试边界。
查看清晰大图先看右侧:测试集从一开始就单独留出。左侧每一行用一个蓝色折做验证,其余绿色折用于拟合;预处理也要在每轮的训练折内重新拟合。测试集不参与选模型,只用于最后评估。图中的五折是过程示例,并非所有任务都应这样切分。
Pipeline 不变量
设训练索引为 ,验证索引为 。任何从数据中学习参数的变换 必须满足:
这涵盖了标准化、缺失值填充、词表构建、PCA、特征选择、目标编码(Target Encoding)、过采样及学习式数据增强。
- 交叉验证(CV): 每个 Fold 内部必须重新 Fit 所有变换。
- 嵌套交叉验证(Nested CV): 外层循环用于评估泛化性能,内层循环用于超参数或特征选择。
- 常见错误: 先在全量数据上做特征选择,再进行 CV,这依然构成泄漏。
一个只用训练数据拟合的变换
scikit-learn 泄漏指南遵循同一规则:在训练数据上学习预处理参数,然后原样应用。假设训练特征值为 2 和 4,验证值为 100。训练集均值为 3,所以验证值中心化后为 97。若全局中心化,均值会变成 ,验证数据便改变了训练样本的表示。
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 选择模型,再根据测试集召回率调整阈值。
稳健设计:
- 冻结信息边界: 明确预测时点及允许使用的字段清单。
- 分组与时间切分: 先按患者分组,再按时间将较晚的 Cohort 留出作为测试集。
- 训练专用 Pipeline: 仅在训练 Cohort 上拟合缺失值填充、词表和特征选择器。
- 验证集调优: 在验证集上选择模型和阈值。
- 单次测试: 测试集仅运行一次,并按医院、时间、关键子群体切片报告结果。
- 标签成熟度检查: 排除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
本文聚焦于离线监督学习场景。在线实验、强化学习、联邦学习和持续学习还涉及干预、反馈和策略泄漏等更复杂的问题,需单独设计。