Data Leakage
数据泄漏会将预测时不可用的信息带入训练或评估,从而虚增分数,导致模型在生产环境中表现不佳。介绍原因和解决方法。
当机器学习(ML)模型的训练数据或评估数据包含模型进行真实预测时无法获取的信息时,就会发生数据泄漏。例如,数据中可能包含来自测试集的样本、未来的数值,或能编码答案的特征。模型在开发和模型测试期间看似准确,到了生产环境却表现不佳,因为它依赖的捷径已经不存在。数据泄漏是结果难以复现的主要原因之一:一项关于基于机器学习的科学研究的调查统计出 17 个领域中有 294 篇受影响的论文;在内战预测任务中,纠正泄漏后,复杂模型相对于几十年前的逻辑回归所报告的优势也消失了。
数据泄漏如何发生#
数据泄漏可能来自数据切分、处理或输入选择的方式;同样的错误会反复出现在表格模型、时间序列分析和动作识别等视觉任务中:
- 训练集与测试集污染:归一化统计量、缺失值填补或特征选择等从数据中学习的步骤,在切分数据之前就使用了整个数据集进行拟合,因此训练数据包含了有关评估集的信息。切分前产生的重复图像和增强副本也会造成同样的影响。
- 分组泄漏:相关样本被拆分到不同集合中,例如同一视频中的连续帧、同一患者的多次扫描,或同一场景的多张照片。模型可能因此通过识别场景或人物而取得高分,而不是学会任务本身。
- 时间泄漏:随机切分按时间排序的数据,或使用预测时点之后的数值计算特征,会让模型看到未来信息。
- 目标泄漏:输入是标签的结果或替代信号,例如用于预测疾病的模型中出现“已接受治疗”字段。
- 重复使用评估集:针对测试集调参,或让大型语言模型的网页规模预训练数据包含基准测试问题,都会使评估数据变成训练信号。
图像也可能携带目标泄漏。在 ChestX-ray14 数据集中,80% 的测试集气胸 X 光片同时显示了胸腔引流管,而这种引流管正是治疗该病症时使用的管子。在有引流管的图像上训练的分类器,其 ROC AUC 达到 0.94;而在没有引流管的图像上只有 0.77,而检测器本来就是要发现尚未接受治疗的病例。
用代码演示数据泄漏#
在交叉验证之前拟合依赖数据的步骤,是教科书式的错误,而且很容易测量其影响。下面的示例生成纯噪声,因此任何模型在新数据上的准确率都不可能超过 50%;随后示例选出最能区分标签的 20 个特征,并对逻辑回归进行两次交叉验证:一次在所有样本上拟合特征选择,另一次则在每个训练折内重新拟合特征选择,并使用 scikit-learn 流水线。
import numpy as np
from sklearn.feature_selection import SelectKBest
from sklearn.linear_model import LogisticRegression
from sklearn.model_selection import cross_val_score
from sklearn.pipeline import make_pipeline
# Pure noise: 100 samples, 5,000 random features, random labels (true accuracy is 50%)
rng = np.random.default_rng(0)
X = rng.normal(size=(100, 5000))
y = rng.integers(0, 2, size=100)
# Leaky: pick the 20 features that best separate the labels using every sample, then cross-validate
X_selected = SelectKBest(k=20).fit_transform(X, y)
leaky = cross_val_score(LogisticRegression(), X_selected, y, cv=5).mean()
# Correct: feature selection is refit inside each training fold
pipeline = make_pipeline(SelectKBest(k=20), LogisticRegression())
clean = cross_val_score(pipeline, X, y, cv=5).mean()
print(f"Leaky CV accuracy: {leaky:.2f}, correct CV accuracy: {clean:.2f}")存在泄漏的版本在随机标签上报告了 85% 的准确率,而流水线版本报告了 48%,即随机水平。对于 5,000 个特征和 100 个样本,一些特征会偶然与标签相关;如果在特征选择时包含验证折,就会把这种偶然相关性带入每个折的得分。
防止数据泄漏#
防范工作从数据切分开始:切分必须先于任何从数据中学习的步骤,这样验证集和测试集才不会被提前看到:
- 在特征工程之前切分数据:只在训练集上拟合缩放器、填补器、编码器和特征选择器,并将它们原样应用于其他数据集。
- 按组或时间切分:同一患者、视频或场景的所有样本都应放在同一个数据集中;用过去的数据训练,用未来的数据测试。
- 使用哈希和嵌入去重:训练前,比较不同数据集间的文件哈希以找出完全相同的副本,并比较嵌入相似度以找出近似重复项。
- 审查输入:确认每个特征在预测时是否已存在;如果某个特征占主导地位,或得分高得可疑,就应将其视为需要调查的错误。
泄漏也会扭曲检查点选择。Ultralytics YOLO会使用数据集 YAML中列出的 train 图像进行训练,并保存验证适应度最高的轮次所对应的 best.pt;对于检测任务,该指标是 mAP50-95。因此,如果 train 和 val 之间存在近似重复帧,就会同时抬高用于选择检查点的分数和最终报告的分数。










