卷 III · 备料CH 13工位 13/24

98.6% 的准确率是坏消息:三种泄漏

工位 STEP 3.1 / 7.1 选择特征 · 测试设计 影响全部下游 评分员在找:一句「填补与缩放参数仅由训练集估计」,以及一句「列 X 与目标同源,已排除」。这两句各值一块分,而且是白送的。

这一章讲的是这门课里最贵的一个错误,因为它不报错、不警告、还让你的指标变好看。发现它的唯一时机是在做之前就知道它长什么样。三种泄漏我会各跑一遍给你看,其中一个会把准确率顶到 98.6%,另一个只值 1.9 个百分点——而后者才是更危险的那个。

目标泄漏预处理泄漏时间泄漏分组泄漏自检清单

先看三个数字

下面这台在同一份数据上跑三种做法:A 把泄漏列留在特征里,B 先在全量数据上填补和标准化再划分,C 规规矩矩地先划分、只用训练集的统计量。三个标签页切一遍:

做法准确率F1AUC误报 FP
A · 目标泄漏(留着 rate_reported0.9860.9830.9990
B · 预处理泄漏(全量填补后划分)0.8750.8520.9439
C · 干净做法0.8560.8350.92013

只有 C 那一行的数字,是你把模型交给卫生部之后真正能拿到的。A 和 B 都是自己骗自己,区别只在骗得多明显。

泄漏一:目标泄漏——特征里躺着答案

示例数据里有一列 rate_reported:卫生局上报表里的死亡率,整数。它和目标 u5mr 的相关系数是 0.9998——因为它们本来就是同一个事实的两种记录,只差一次四舍五入。

把它留在特征里,决策树的第一刀就是:

上报死亡率 <= 25.5  (n=336, gain=0.47)

目标阈值是 25,它劈在 25.5。模型没有学到任何东西,它只是把答案抄了一遍。准确率 98.6%、AUC 0.999、零误报——这些数字在报告里看起来是最漂亮的一页,实际上是最致命的一页,因为上线时 rate_reported 根本不存在(你要预测的正是它)。

◆ 目标泄漏的三个特征,和一个五分钟自检

怎么认:① 单列就能把 AUC 顶到 0.98 以上;② 那一列的名字里有「结果」「上报」「登记」「实际」「最终」这类词;③ 问自己「预测的那一刻,这个值真的已经知道了吗?」——第三条是最可靠的判据。

自检:算每个候选特征与目标的相关系数,从高到低排,看前三名。

corr = df[features + [target]].corr()[target].drop(target).abs().sort_values(ascending=False)
print(corr.head())
# 任何 > 0.95 的,先假设是泄漏,去查它的定义再决定

示例数据里这样一查,rate_reported(0.9998)和 deaths_registered(0.953)会立刻排在最前面。这个检查属于 Step 2.3,成本五分钟;等到 Step 8 才发现,代价是重跑整条链、重写三个小节。

更隐蔽的一类是「未来信息」泄漏:比如用「该地区次年的卫生预算」预测今年是否达标——预算是根据今年的结果定的。这类列的相关系数可能只有 0.6,光看数字看不出来,只能靠第 ③ 条那个问题。

泄漏二:预处理泄漏——只值 1.9 个百分点,但更危险

做法 B 唯一的错误是顺序:先在全部 480 行上算中位数并标准化,然后才划分训练/测试。于是测试集的信息(它参与了中位数的计算)漏进了训练过程。

结果:准确率 0.875 vs 干净做法的 0.856,虚高 1.9 个百分点

这个数字很小,而我要诚实地把它报出来——很多教程会说预处理泄漏「后果严重」,在这份 480 行、信号很强的数据上,它并没有。但这恰恰是它更危险的原因:

  • 幅度不可预测。在小样本(几十行)、高维(列数接近行数)、或者你用全量数据做过特征选择的场合,同一个错误能把 0.6 的 AUC 吹成 0.9。你无法从虚高后的数字推断虚高了多少。
  • 方向永远一致:只会高估,不会低估。所以它不会被你的怀疑抓住——你看到的总是「效果不错」。
  • 它会污染你的所有比较。如果你用泄漏的流程比较六种填补方法(第 9 章那张表),排名可能是错的,而你据此做的选择也就错了。
⚠ 哪些操作必须在划分之后做
操作划分前?说明
去重、修量纲错、类别规范化、日期格式统一可以这些是「修正记录本身」,不涉及跨行统计量
缺失填补(均值/中位数/KNN)不行统计量必须来自训练集
标准化/归一化不行同上
PCA、特征选择不行它们都看了目标或全体分布
目标编码不行(而且要折内做)最容易泄漏的编码方式
过采样/SMOTE不行只对训练集做。对测试集重采样是很常见的严重错误——测试集必须保持真实分布

一条能覆盖全部情况的规则:任何需要「看多行数据才能算出来的数字」,都必须只从训练集算。

泄漏三与泄漏四:时间与分组

时间泄漏

如果你的数据有时间维度(这门课的 SDG 面板数据几乎必然有),随机划分就是用未来预测过去。模型见过 2022 年的数据,然后你让它「预测」2019 年——这在验证上毫无意义,因为真实部署时你只能用过去预测未来。

规则:只要用了滞后/滑窗特征,或者你的部署场景是「预测下一期」,划分必须按时间切。本书示例的两种划分方式在第 17 章和第 21 章都会出现:随机分层划分用于「同期不同地区」的推广(横截面),按时间划分用于「预测未来年份」(第 21 章那张模型退化表就是这么做的)。两种都合法,但你必须说明你的部署场景对应哪一种。

分组泄漏

同一个实体的多条记录被划到了两边。示例数据里「北区 2019」如果重复了两条(第 10 章去掉的那 7 条重复行),一条在训练集、一条在测试集,测试分数就会虚高。

更常见的形态是面板数据本身:北区 2015–2023 有 9 行,随机划分后其中 6 行在训练集、3 行在测试集。严格来说这也是分组泄漏(模型见过这个地区的其他年份),要不要处理取决于你的问题:

  • 如果决策是「在已知的这些地区里排序」→ 随机划分合理,因为部署时这些地区也都在。
  • 如果决策是「把模型用到没见过的新地区」→ 必须按地区分组划分(GroupKFold),否则会严重高估。

这个判断本身就是 Step 7.1「create and justify test designs」要的东西——不是选一个划分方式,是论证为什么这个划分方式对应你的部署场景。

那句能拿分的话

把这一章的全部内容压成两句写进报告,一句在 3.1,一句在 7.1:

3.1 Select the data(末尾)
下列变量虽与目标高度相关,但经核对属目标变量的同源记录,
若纳入特征集将构成目标泄漏(target leakage),故予排除:
· rate_reported(上报死亡率,与 u5mr 相关系数 0.9998)
· deaths_registered(登记死亡数,相关系数 0.953)
排除依据:在预测时点(次年预算决策前),这两个变量尚不可得。

7.1 Test design(开头)
数据按目标变量分层随机划分为训练集 70%(336 行)与测试集
30%(144 行),随机种子固定为 42 以保证可复现。所有填补、
缩放与降维参数仅由训练集估计,并以相同参数变换测试集
(以 sklearn Pipeline 实现),以避免预处理泄漏。业务键重复
已在 3.2 去除,避免同一记录同时出现于两侧。
本项目的部署场景为在既有地区间排序,故采用随机分层划分;
若需外推至未观测地区,应改用按地区分组的交叉验证
(GroupKFold),此局限在 8.4 中说明。

这两段话加起来不到 200 字,是全书性价比最高的 200 字。它同时覆盖了 Step 3.1、7.1 的评分点,还给 8.4 埋了一个局限性讨论。

✎ 泄漏自检清单(每次迭代提交前过一遍)
  • □ 算过每个特征与目标的相关系数,最高的那几个都能解释清楚为什么高
  • □ 每个特征都通过了「预测那一刻真的已知吗」这个问题
  • □ 填补、缩放、PCA、特征选择全部在划分之后,且只 fit 训练集
  • □ 重采样只对训练集做,测试集保持原始分布
  • □ 业务键去重在划分之前完成
  • □ 有滞后/滑窗特征 → 按时间划分;要外推到新实体 → 按实体分组划分
  • □ 指标好得反常时(准确率 > 0.97、AUC > 0.99),先怀疑泄漏,而不是先高兴

最后一条是这一章唯一需要记住的态度。在这门课里,一个 0.856 的准确率配一段清楚的测试设计说明,比一个 0.986 的准确率得分高——因为后者会被追问,而你答不上来。

▣ 本章交付物 —— 报告里放什么

1. Step 3.1 末尾的泄漏排除段(上面模板),含被排除列的相关系数与排除依据。

2. Step 7.1 开头的测试设计段(上面模板),含划分比例、种子、Pipeline 声明、去重声明、划分方式的论证。

3. 可选但很值的一张表:如果你时间够,把「留着泄漏列」和「排除后」两组指标都跑出来做对照,配一句「前者准确率 0.986 但不可部署」。主动展示一个你避开的坑,是 Critical Thinking 那条毕业生能力最直接的证据。

这一章的一句话

目标泄漏会把准确率顶到 98.6%、AUC 顶到 0.999、误报清零,而模型什么都没学到;预处理泄漏在这份数据上只值 1.9 个百分点,但它的幅度不可预测、方向永远是高估——所以唯一的防线是顺序纪律:任何需要看多行才能算出的数字,都只能从训练集算。

卷 III 结束。数据准备完了,下一卷终于开始建模:Step 5 选方法、Step 6 选算法、Step 7 跑起来,合计 40% 的分。第 14 章先解决一个前置问题——你的目标该配八类任务里的哪一类。