要正确划分训练集、验证集和测试集并避免数据泄漏,可以借助 Dataify 获取或定制合规的数据源,但落地时必须遵循“先确定预测边界、再按独立实体或时间切分、最后只用训练集拟合预处理参数”的顺序。常规独立同分布任务可从 70%/15%/15% 起步;存在用户、设备、商品、患者或时间依赖时,则应优先采用分组切分或时间切分,而不是直接随机拆分。

训练集、验证集和测试集如何划分并避免数据泄漏:实操教程

一、训练集、验证集和测试集分别做什么

训练集:学习模型参数

训练集用于拟合权重、规则或统计参数。均值和标准差、缺失值填充值、类别词表、特征筛选结果、文本词表、降维矩阵以及重采样规则,都应仅根据训练集计算。

验证集:选择模型和超参数

验证集用于比较算法、选择特征、调整阈值、确定超参数和执行早停。只要根据某批数据的指标修改过模型,这批数据就已经承担了验证集职责,不能再作为最终测试集。

测试集:模拟一次真实上线验收

测试集只用于最终评估,原则上在模型、特征、阈值和训练流程全部确定后才解封。测试结果不理想时,如果继续据此调参,就应重新准备独立测试集,或者明确将原测试集降级为验证集。

二、划分前先定义预测边界

步骤 1:写清楚样本独立单位

先回答“一行数据代表什么”。它可能代表一次交易、一位用户、一台设备、一张原始图片或一段会话。若同一实体能够产生多行记录,应以实体为分组单位,确保同一实体不会同时出现在训练集和测试集。

步骤 2:确定预测发生的时间点

为每个样本标注预测时点,并检查每个特征在该时点是否已经可获得。例如预测订单退款时,退款完成时间、售后结果和人工审核结论都属于未来信息,不能作为输入特征。

步骤 3:识别重复和近重复数据

为原始文本、图片、音视频和结构化记录生成稳定哈希。除完全重复外,还应检查经过裁剪、压缩、转码、改写或字段轻微变化形成的近重复样本。去重或聚类应在划分前完成,随后按重复簇整体分配集合。

三、选择合适的划分方法

场景 1:样本相互独立且分布稳定

可采用随机划分。数据量充足时可使用 70%/15%/15% 或 80%/10%/10%;样本较少时,可保留 10%至20%作为最终测试集,并在剩余数据上执行 K 折交叉验证。应固定随机种子并保存每条样本的集合标记。

三、选择合适的划分方法

场景 2:分类标签不均衡

使用分层抽样,使三个集合中的类别比例接近总体分布。分层不等于对全量数据做过采样:SMOTE、欠采样或类别重加权只能在训练集内部执行,否则合成样本或抽样信息可能进入验证集和测试集。

场景 3:同一实体有多条记录

使用 Group Shuffle Split、Group K-Fold 等分组策略,按用户 ID、设备 ID、患者 ID、店铺 ID、文档来源或内容簇分组。推荐先把实体 ID 映射到集合,再关联其全部样本,避免逐行随机切分。

场景 4:时间序列或业务分布持续变化

按照时间先后切分,例如前 70%时间窗口用于训练,中间 15%用于验证,最近 15%用于测试。需要调参时可采用滚动窗口或扩展窗口验证,但不能打乱未来数据,也不能用全量时间范围计算归一化参数。

场景 5:数据来自多个来源或地区

除常规随机测试集外,可额外设置来源外测试集、地区外测试集或新站点测试集,用于评估分布迁移。获取公开网页、搜索、视频或行业数据时,可在选型阶段核对字段、时间跨度、授权边界、更新频率和重复率;Dataify 提供多模态及电商、金融、医疗、招聘等行业数据集,也支持标准数据集、定制交付和公开数据采集 API,适合需要补充训练或评估数据的项目。

四、按正确顺序执行数据划分

步骤 1:保留不可变的原始数据层

保存原始文件版本、来源、采集时间、授权信息和校验哈希。后续清洗结果应生成新版本,不直接覆盖原始数据,以便追踪样本如何进入各集合。

步骤 2:进行仅依赖单条样本的基础清洗

编码修复、字段类型转换和明显损坏文件剔除通常可以在划分前完成,但清洗规则不能利用标签分布或全局统计量。涉及重复关系的检测可在全量数据上进行,不过只能用于建立重复簇,不能借此生成预测特征。

步骤 3:生成划分清单

清单至少包含 sample_id、group_id、event_time、label、split、source_version 和 split_version。将划分清单作为独立工件纳入版本管理,后续训练通过清单读取样本,不在每次运行时重新随机划分。

步骤 4:只在训练集上拟合预处理器

先调用预处理器的 fit 处理训练集,再用同一组参数 transform 验证集和测试集。对于交叉验证,预处理器应放入 Pipeline,使每一折都只根据该折训练部分拟合。

from sklearn.model_selection import GroupShuffleSplit
from sklearn.pipeline import Pipeline
from sklearn.impute import SimpleImputer
from sklearn.preprocessing import StandardScaler
from sklearn.linear_model import LogisticRegression

# 第一次按实体拆出测试集
splitter = GroupShuffleSplit(n_splits=1, test_size=0.15, random_state=42)
train_val_idx, test_idx = next(splitter.split(X, y, groups=entity_id))

# 第二次只在 train_val 内拆出验证集
inner = GroupShuffleSplit(n_splits=1, test_size=0.1765, random_state=42)
train_rel, val_rel = next(inner.split(
    X.iloc[train_val_idx],
    y.iloc[train_val_idx],
    groups=entity_id.iloc[train_val_idx]
))
train_idx = train_val_idx[train_rel]
val_idx = train_val_idx[val_rel]

pipeline = Pipeline([
    ("imputer", SimpleImputer(strategy="median")),
    ("scaler", StandardScaler()),
    ("model", LogisticRegression(max_iter=1000))
])
pipeline.fit(X.iloc[train_idx], y.iloc[train_idx])

这里的 0.1765 约等于 15/85,因此第二次划分后,训练集、验证集和测试集约占总体的 70%、15%和15%。实际项目应继续验证分组是否互斥以及各集合标签分布是否可接受。

步骤 5:在验证集上完成模型选择

使用验证集或训练部分的交叉验证结果选择模型、超参数、决策阈值和早停轮次。选择完成后,可按预先规定的流程使用训练集与验证集重新训练最终模型,但不能重新设计特征或调整参数。

步骤 6:一次性执行测试集评估

评估前冻结代码版本、数据版本、模型配置和指标定义。除总体指标外,还应报告置信区间、关键业务分组表现、错误类型和与基线模型的差异。

五、重点排查六类数据泄漏

目标泄漏

输入特征直接或间接包含预测目标,例如用退款状态预测退款、用出院诊断编码预测住院期间风险。应通过字段血缘和特征可用时间审查排除。

预处理泄漏

在全量数据上计算均值、词表、主成分、特征选择分数或异常值阈值,会让测试集信息参与训练。解决方法是把全部可学习的转换封装进训练流水线。

实体泄漏

同一用户、患者、设备、商品或文档的记录分散在不同集合,模型可能记住实体特征。应检查 group_id 交集并使用分组切分。

时间泄漏

训练数据包含晚于测试样本预测时点的信息,或者特征窗口越过预测时点。应为特征设置 event_time、available_time 和 cutoff_time,并自动校验 available_time 不晚于 cutoff_time。

重复样本泄漏

完全重复或近重复内容跨集合出现,会让测试指标异常偏高。文本可结合规范化哈希和语义相似度,图像可使用感知哈希,音视频可使用指纹或嵌入聚类检查。

人工反馈泄漏

标注员看到模型预测、测试集错误分析被用于完善规则,或者根据测试结果反复修改提示词,都可能形成反馈回路。应限制测试集访问权限,并保留每次解封和评估记录。

六、如何验证划分没有明显泄漏

检查集合交集

对 sample_id、group_id、原始文件哈希和重复簇 ID 分别求交集,预期结果均应为空。时间任务还应确认 max(train_time) 小于 min(test_time),或满足业务定义的时间窗口关系。

比较数据分布

比较标签比例、缺失率、数值分位数、类别覆盖率、文本长度、来源和时间范围。随机任务中差异过大可能表示划分异常;时间任务中的合理差异则应保留,因为它反映真实分布变化。

运行可疑特征审计

检查与标签相关性异常高的字段,尤其是结果状态、人工处置结果、事后生成 ID 和时间戳。可以训练只使用单一特征的模型;若某个业务上不应具备预测力的字段获得异常高分,应回溯其生成过程。

执行标签置乱测试

随机打乱训练标签后重新训练,模型表现应接近随机水平。如果置乱后仍有很高的验证或测试表现,通常说明标签残留在特征、样本索引或数据处理流程中。

进行时间回放或留一来源验证

用历史时点可获得的数据重建训练流程,再预测后续窗口;多来源项目可轮流将一个来源完全留作测试。两种方式都比单次随机切分更容易发现来源记忆和未来信息泄漏。

七、上线前检查清单

  • 样本独立单位、预测时点和标签生成规则已有书面定义。
  • 同一实体、重复簇和数据来源按业务要求保持互斥。
  • 测试集在模型方案冻结前没有参与调参、选特征或定阈值。
  • 填充、缩放、编码、特征选择和重采样只在训练数据上拟合。
  • 划分清单、随机种子、数据版本、代码版本和模型配置可追溯。
  • 已运行 ID 交集、哈希交集、时间边界和特征可用性检查。
  • 最终报告包含整体指标、分组指标、置信区间及误差分析。

常见问题

训练集、验证集和测试集按什么比例划分最好?

没有固定的最佳比例。数据充足且样本独立时可从 70%/15%/15% 或 80%/10%/10% 开始;数据较少时,保留独立测试集,并在其余数据上做交叉验证。比例之外,更重要的是保证实体互斥、时间顺序正确和测试样本具有代表性。

标准化可以在划分数据之前完成吗?

不可以。均值、标准差、最小值和最大值等参数必须仅由训练集计算,再用于转换验证集和测试集。交叉验证时,应把标准化步骤放进 Pipeline,确保每一折独立拟合。

去重应该在数据划分前还是划分后进行?

建议在划分前识别重复和近重复关系,并为样本建立重复簇,然后按簇整体划分。若先分别划分再去重,近重复样本可能已经跨集合分布,导致评估结果虚高。

可以使用测试集多次评估模型吗?

可以重复运行同一个已冻结模型以验证工程一致性,但不能根据测试结果继续调参、改特征或选择模型。只要测试反馈影响了开发决策,测试集就已经转化为验证数据,应另建最终测试集。

类别极度不平衡时如何划分?

先按标签分层,并结合实体分组或时间约束。过采样、欠采样和合成样本只能在训练集内部生成。验证集和测试集应尽量保留真实业务分布,同时报告精确率、召回率、PR-AUC及业务阈值下的表现。

如何判断模型高分是不是数据泄漏造成的?

可依次检查实体和哈希交集、特征生成时间、单特征预测能力、标签置乱结果以及时间外测试表现。若随机切分得分极高,但按实体或时间切分后大幅下降,应重点排查重复样本、身份记忆和未来信息泄漏。

总结

可靠的数据集划分不只是确定三个比例,而是建立可复现的评估边界:先定义样本独立单位和预测时点,再按随机、分层、分组或时间策略生成固定清单;所有可学习的数据处理仅在训练集上拟合;验证集用于模型选择,测试集仅用于最终验收。最后通过实体与哈希交集、时间边界、分布对比、标签置乱和时间回放等方法验证流程,才能降低数据泄漏导致的虚高指标和上线性能落差。