📑 本页目录(点开跳转)
07 · 没有标签怎么发现退化
⏱ 42 分钟 | ⭐⭐ 最容易被忽略的盲区
🎯 一句话
教科书假设你知道对错,现实里你常常不知道。 退货要等 7 天、欺诈要等 30 天、用户会不会续费要等一年 —— 这段时间里,你靠什么判断模型还活着?
⏳ 一、标签延迟有多常见
| 场景 | 标签什么时候到 | 延迟 |
|---|---|---|
| 点击率预估 | 几秒内 | ✅ 几乎实时 |
| 转化率预估 | 用户下单后 | 小时~天 |
| 退货预测 | 收货 7 天后 | 1–2 周 |
| 信贷违约 | 首次逾期 | 1–3 个月 ⭐ |
| 欺诈 | 用户投诉 / 对账 | 数周,且很多永远不来 ⭐⭐ |
| 续费预测 | 合同到期 | 1 年 |
🔑 注意欺诈那一行:很多标签永远不会来。 没被发现的欺诈,在你的数据里就是「正常交易」—— 你的标签本身就是有偏的,这是比延迟更深的问题(见第五节)。
⭐ 一个残酷的算术:
信贷模型标签延迟 3 个月
→ 你今天发现的问题,是 3 个月前就开始的
→ 这 3 个月里放出去的所有贷款,都已经是坏决策了
🧭 二、没有标签时,能看什么(五种代理信号)
按「有多接近真实指标」排序:
① 输入侧:特征分布漂移 ← 第 6 章,最早的信号
② 输出侧:预测分布变化 ← 第 5 章
③ 行为侧:用户对结果的即时反应 ⭐ 最有价值
④ 一致性:模型之间互相验证 ⭐
⑤ 抽样:人工标一小批 ← 最准,最贵
③ 行为侧代理:找一个「早期标签」⭐⭐
核心思路:真实标签来得晚,但和它相关的某个行为来得早。
| 最终标签(慢) | 早期代理(快) | 相关性 |
|---|---|---|
| 是否退货(2 周) | 是否点了「查看退货政策」(当天) | 中 |
| 是否违约(3 个月) | 首期是否按时还(1 个月) | 高 ⭐ |
| 是否续费(1 年) | 月活跃天数、核心功能使用率(当月) | 中高 |
| 是否欺诈(数周) | 风控规则命中数、设备异常分(实时) | 中 |
⭐ 用法不是「用代理替代真实标签」,而是:
① 用【历史数据】算出代理和真实标签的相关性
② 只要这个相关性是稳定的,就能用代理做【早期预警】
③ 代理指标异动 → 提前几周知道要出事
④ 真实标签到了之后,回头验证代理是否还可靠 ⭐
⚠️ 第 ④ 步不能省:代理和真实标签的关系本身也会漂移。 每次真实标签到齐后,都要重新算一次相关性 —— 否则你会依赖一个已经失效的代理。
④ 一致性检查:让模型互相验证 ⭐
三种做法,都不需要标签:
A. 新旧模型对比
同一批请求,新旧模型的预测差异突然变大
→ 至少有一个出问题了
B. 冠军-挑战者(champion-challenger)
线上跑主模型,同时用影子流量跑一个【简单模型】(如逻辑回归)
→ 简单模型不容易坏,可以当参照系 ⭐
→ 两者差异突然变大 = 复杂模型可能出问题了
C. 自洽性检查
同一个用户,特征只变了一点点,预测却剧烈变化
→ 模型不稳定
⭐ B 特别值得做:一个简单模型作为「基线哨兵」。 它的效果一定不如主模型,但它的稳定性是主模型的参照系。 成本很低(逻辑回归几乎不占资源),价值很高。
⑤ 人工抽样:最准的那把尺子
每天/每周随机抽 100~500 条,人工标注真实答案
→ 得到一个【小样本但无延迟】的准确率估计
⭐ 关键设计:
· 必须【随机抽】,不能只抽模型不确定的(那会高估错误率)
· 要固定流程和标注规范,否则标注本身会漂
· 样本量要够算出可用的置信区间(第 12 章会讲怎么算)
💡 一个省钱的技巧:分层抽样
按模型预测的置信度分层,每层抽一些:
· 高置信层抽少一点(错的概率低)
· 低置信层抽多一点(信息量大)
→ 再按层的占比加权还原总体准确率
⭐ 同样的标注预算,估计精度明显更高
🔬 三、把它们组合成一套预警体系
时间轴 ────────────────────────────────────────────►
T+0 特征分布漂移告警 ← 最快,但可能误报
T+0 预测分布异常
T+1天 行为代理指标异动 ⭐
T+1周 人工抽样准确率下降
T+3月 真实标签确认 ← 最准,但太晚
⭐ 越早的信号越不准,越晚的越准
→ 早期信号用来【触发调查】,不用来【自动回滚】
🔑 这条时间轴决定了告警该怎么设计: T+0 的信号 → 通知人去看一眼(因为它可能误报) T+1周 的信号 → 可以触发回滚决策 把早期信号接成自动回滚,会因为频繁误报而被关掉(第 8 章)。
💀 四、一个特别的陷阱:模型自己制造的标签缺失
风控模型拒绝了一笔贷款
→ 这笔贷款没有发生
→ 【永远不会知道】它会不会违约 💀
→ 你的训练数据里,只有【被通过的】那些人的标签
→ 模型只在"它自己认为安全的"人群上学习
这叫「拒绝推断」(reject inference)问题,本质上是第 1 章那个反馈闭环的极端形式。
三种常见缓解:
| 做法 | 说明 | 代价 |
|---|---|---|
| 随机放行一小部分 ⭐ | 对被拒绝的人随机通过 1%,拿到无偏标签 | 真实损失,但是唯一能拿到干净数据的办法 |
| 用外部数据补 | 征信、第三方数据看他在别处的表现 | 有合规限制 |
| 建模推断 | 用统计方法估计被拒人群的表现 | 依赖假设,可能自我强化 |
🔗 注意第一条和第 2 章的「留 1% 随机流量」是同一个思想: 主动付出一点代价,换一批没有被模型污染的数据。 在推荐里它对抗幸存者偏差,在风控里它对抗拒绝推断。
📋 五、可以照抄的落地清单
[ ] 弄清每个标签的实际延迟(很多团队从没量过)⭐
[ ] 找到 1-2 个行为代理指标,并算出它和真实标签的历史相关性
[ ] 上线一个简单模型当「基线哨兵」(冠军-挑战者)⭐
[ ] 建立人工抽样流程,固定频率和标注规范
[ ] 留一小份随机流量/随机放行,作为无偏数据源 ⭐⭐
[ ] 画出你的「信号时间轴」,明确哪个信号触发什么动作
[ ] 真实标签到齐后,回头验证代理指标是否仍然可靠
⭐ 第一条最容易被跳过,也最重要: 很多团队根本不知道自己的标签延迟是多少。 量一下(画个标签到达时间的分布图),你会发现它比想象的长, 而且有很长的尾巴。
💀 六、代理指标最危险的失效方式:模型把它优化坏了
前面说"代理和真实标签的关系会漂移"。最狠的一种漂移,是你自己造成的。
某内容平台,真实目标是【次日留存】(要等一天)
选了【完播率】当代理指标(几秒内就有)
历史相关性 r = 0.61 —— 看起来是个不错的代理 ✅
三个月后,模型开始把完播率当优化目标之一:
→ 短视频天然完播率高 → 推荐里短视频占比从 31% 涨到 68%
→ 完播率从 42% 涨到 54%(+12pp)🎉
→ 次日留存却从 38.5% 掉到 37.3%(−1.2pp)💀
→ 重新算相关性:r 从 0.61 掉到 0.08
| 时点 | 完播率 | 次日留存 | 两者相关性 |
|---|---|---|---|
| 选定代理时 | 42% | 38.5% | 0.61 ✅ |
| 三个月后 | 54% | 37.3% | 0.08 💀 |
⭐⭐ 这是 Goodhart 定律的教科书案例: 一个指标一旦变成优化目标,它就不再是个好指标。 代理之所以能当代理,是因为在原来的策略下它和真实目标相关; 而模型改变了策略本身。
🔑 三条防线: 1. 代理指标只用来"预警",不用来"优化" —— 一旦它进了损失函数或排序公式,它就死了。 2. 定期重算相关性(至少每月),把 r 本身画成一条曲线监控起来。 3. 留一份不受模型影响的对照:一小份随机流量上,代理和真实指标的关系是干净的。
🔗 第 15 章专门讲代理指标和长期效应,这里是它的入口。
🔨 七、三段可以直接跑的代码
① 先量一下你的标签延迟到底是多少
第五节说"很多团队从没量过"。量它只要几行:
import pandas as pd, numpy as np
def label_delay_profile(df, t_pred="predict_time", t_label="label_time"):
"""df 里每行是一次预测;label_time 为空 = 标签还没来"""
arrived = df[t_label].notna()
d = (df.loc[arrived, t_label] - df.loc[arrived, t_pred]).dt.total_seconds() / 86400
print(f"标签到达率 {arrived.mean():.1%}") # ⭐ 这个数常常远小于 100%
for q in [.5, .8, .9, .95, .99]:
print(f" P{int(q*100):<3} {d.quantile(q):6.1f} 天")
# ⭐ 关键:右侧尾巴有多长决定了你的"评估窗口"该留多久
print(f" 最长 {d.max():.1f} 天")
return d
一个真实场景跑出来的结果(退货预测):
标签到达率 93.2% ← ⚠️ 有 6.8% 永远不会来
P50 2.1 天
P80 6.8 天
P90 11.4 天
P95 19.7 天 ← ⭐ 尾巴比想象长得多
P99 58.3 天
⭐ 结论:如果你按"7 天后统计准确率",
实际只覆盖了 80% 的样本,而且【漏掉的那 20% 系统性偏向慢退货】
→ 你算出来的准确率是【乐观偏差】的
② 冠军-挑战者的差异监控
from scipy.stats import spearmanr
def champion_challenger_gap(p_main, p_simple, base_gap):
"""p_main / p_simple: 同一批请求上两个模型的预测分数"""
# ⭐ 用【排序相关性】而不是绝对差值——两个模型的分数尺度本来就不同
rho = spearmanr(p_main, p_simple).statistic
mean_shift = abs(p_main.mean() - p_simple.mean())
alerts = []
if rho < base_gap["rho"] - 0.15: # ⭐ 和历史基线比,不是和 1.0 比
alerts.append(f"两模型排序相关性 {base_gap['rho']:.2f}→{rho:.2f}")
if mean_shift > base_gap["shift"] * 2:
alerts.append(f"两模型均值差扩大到 {mean_shift:.3f}")
return alerts
⚠️ 一个必须提前想清楚的问题:差异变大时,是谁坏了? 单看这一个信号回答不了。但它能把范围从"整个系统"缩小到"这两个模型之一", 再结合特征漂移(第 6 章)就能定位。 哨兵的价值是缩小搜索空间,不是直接给答案。
③ 分层抽样的权重还原
def stratified_accuracy(labels, preds, strata, strata_pop_share):
"""strata: 每条抽样样本所属的层;strata_pop_share: 各层在总体中的占比"""
acc, se2 = 0.0, 0.0
for s, w in strata_pop_share.items():
m = strata == s
if m.sum() < 5: # ⭐ 层内样本太少,估计不可信
print(f"⚠️ 层 {s} 只有 {m.sum()} 条")
a = (labels[m] == preds[m]).mean()
acc += w * a
se2 += (w ** 2) * a * (1 - a) / max(m.sum(), 1) # ⭐ 方差也要按权重合成
return acc, se2 ** 0.5 # 返回 (加权准确率, 标准误)
🧭 八、按标签延迟选方案(决策表)
| 你的标签延迟 | 主力手段 | 辅助 | 别做什么 |
|---|---|---|---|
| < 1 小时 | 直接看真实指标 | 特征漂移兜底 | 别为它建复杂的代理体系 |
| 1 天 ~ 1 周 | 行为代理 + 每日真实指标 ⭐ | 冠军-挑战者 | 别按小时看真实指标(样本不够) |
| 1 周 ~ 1 月 | 人工抽样 + 行为代理 ⭐⭐ | 特征漂移、哨兵模型 | 别等标签齐了才评估 |
| > 1 月 | 随机放行/随机流量 + 早期代理 ⭐⭐ | 全部手段都要上 | 💀 别只靠真实标签做决策 |
| 标签有系统性缺失(欺诈、风控) | 随机放行是唯一干净来源 | 外部数据交叉验证 | 💀 别用有偏标签算"准确率" |
⚠️ 无标签监控的五个坑:
| 坑 | 后果 | 怎么修 |
|---|---|---|
| 代理指标进了损失函数 | Goodhart,代理失效且不可逆 💀 | 代理只用于预警 ⭐ |
| 抽样只抽模型不确定的 | 高估错误率,看起来一直在恶化 | 严格随机 + 分层 |
| 按"标签已到达"的样本算指标 | 乐观偏差(慢标签系统性缺席)⭐ | 固定观察窗口,窗口内未到达的按规则处理 |
| 哨兵模型也跟着重训 | 两个模型一起漂,参照系失效 💀 | 哨兵长期冻结,只在明确的时点更新 ⭐ |
| 标注规范没写下来 | 标注本身在漂,指标变化分不清来源 | 固定规范 + 定期一致性抽检 |
⭐ 第四条特别值得记:哨兵模型的价值来自"它不变"。 一旦你也定期重训它,它就和主模型一起漂走了 —— 参照系没了。
🔗 九、和站内其他章的关系
| 相关的地方 | 和这一章的关系 |
|---|---|
| 第 2 章留随机流量 | 同一思想的另一个应用 |
| 第 6 章概念漂移 | 它需要标签,所以才有这一章 |
| 推荐算法 02反馈闭环 | 拒绝推断是它的极端形式 |
| 推荐算法 13探索 | 随机放行 = 探索的风控版 |
✅ 检查点
- 标签延迟为什么是个严重问题?用信贷的例子说明。
- 欺诈场景的标签有什么比"延迟"更深的问题?
- 五种代理信号是什么?按什么排序的?
- 行为代理的正确用法是什么?哪一步不能省?为什么?
- 「冠军-挑战者」为什么值得做?
- 人工抽样为什么必须随机抽?分层抽样怎么省钱?
- 为什么早期信号不该接自动回滚?
- 什么是拒绝推断?唯一能拿到干净数据的办法是什么?
- 「完播率」那个事故里发生了什么?它是什么定律的案例?三条防线是什么?
- 量标签延迟时,为什么要看 P95 而不只是中位数?「按 7 天统计准确率」会有什么偏差?
- 冠军-挑战者的差异为什么要用排序相关性而不是绝对差值?这个信号能回答"是谁坏了"吗?
- 标签延迟超过一个月时,主力手段应该是什么?
- 为什么哨兵模型不能跟着重训?
👀 答案
- 因为你今天发现的问题是延迟那么久之前就开始的。信贷延迟 3 个月 → 这 3 个月里放出去的所有贷款都已经是坏决策了。
- 很多标签永远不会来——没被发现的欺诈在数据里就是"正常交易",标签本身就是有偏的。
- ①特征分布漂移 ②预测分布变化 ③行为侧即时反应 ④模型间一致性 ⑤人工抽样。按有多接近真实指标排序。
- 用法是用历史数据算出代理和真实标签的相关性,只要相关性稳定就能做早期预警。不能省的是最后一步:真实标签到了之后回头验证代理是否还可靠——因为代理和标签的关系本身也会漂移。
- 因为简单模型不容易坏,可以当参照系;它效果不如主模型,但稳定性是主模型的参照系。成本极低(逻辑回归几乎不占资源)。
- 必须随机抽是因为只抽模型不确定的会高估错误率。分层抽样:按置信度分层,高置信层少抽、低置信层多抽,再按占比加权还原——同样预算精度更高。
- 因为越早的信号越不准、可能误报;接成自动回滚会因频繁误报而被关掉。早期信号应该触发调查而不是自动动作。
- 风控拒绝了一笔贷款 → 它没发生 → 永远不知道会不会违约,训练数据里只有被通过的人。唯一能拿到干净数据的办法是随机放行一小部分(付出真实损失换无偏标签)。
- 完播率被选为次日留存的代理(r=0.61),但模型开始优化它之后,短视频占比从 31% 涨到 68%,完播率 42%→54% 而次日留存 38.5%→37.3%,相关性掉到 0.08。这是 Goodhart 定律:一个指标一旦变成优化目标,它就不再是个好指标——代理能当代理是因为"在原来的策略下"相关,而模型改变了策略本身。三条防线:①代理只用来预警,绝不进损失函数/排序公式 ②定期重算相关性并把 r 本身监控起来 ③留一份不受模型影响的随机流量做干净对照。
- 因为尾巴比想象长得多(真实例子:P50 只有 2.1 天,但 P95 是 19.7 天、P99 是 58.3 天,还有 6.8% 永远不来)。按 7 天统计只覆盖约 80% 的样本,而漏掉的 20% 系统性偏向慢退货 → 算出来的准确率有乐观偏差。
- 因为两个模型的分数尺度本来就不同,绝对差值没有可比性;而且要和历史基线比,不是和 1.0 比。它回答不了"是谁坏了"——但它能把范围从"整个系统"缩小到"这两个模型之一"。哨兵的价值是缩小搜索空间,不是直接给答案。
- 随机放行 / 随机流量 + 早期代理,且全部辅助手段都要上。绝不能只靠真实标签做决策——等它到齐时损失早已发生。
- 因为哨兵的价值来自"它不变"。一旦跟着定期重训,它就和主模型一起漂走了,参照系就没了。应该长期冻结,只在明确的时点更新。
🛑 可以停在这里
⚡ 走神救援
⭐⭐教科书假设你知道对错,现实里常常不知道:退货等2周、违约等3个月、续费等1年。⭐残酷算术:延迟3个月意味着你今天发现的问题3个月前就开始了,这期间的决策全是坏的。⚠️欺诈更深的问题:很多标签永远不会来——没被发现的欺诈在数据里就是"正常交易",标签本身有偏。五种代理信号(按接近真实指标排):特征漂移 → 预测分布 → ⭐行为代理 → 模型间一致性 → 人工抽样。⭐行为代理:找个来得早、和最终标签相关的行为(违约→首期是否按时还);用法是先用历史数据算相关性,且真实标签到齐后必须回头验证代理是否还可靠(关系本身也会漂)。⭐冠军-挑战者:影子流量跑个简单模型当基线哨兵——它效果差但稳定性是主模型的参照系,成本极低。人工抽样必须随机(只抽不确定的会高估错误率),分层抽样同预算精度更高。⭐信号时间轴决定告警设计:早期信号触发调查、不接自动回滚(会因误报被关掉)。💀拒绝推断:拒绝的贷款永远不知道会不会违约 → 唯一干净办法是随机放行一小部分,和第2章"留1%随机流量"是同一个思想。💀⭐⭐代理指标最狠的失效方式是你自己造成的:完播率当次日留存的代理(r=0.61),模型开始优化它后短视频占比 31%→68%,完播率涨 12pp 而次日留存跌 1.2pp,相关性掉到 0.08 —— 这就是 Goodhart 定律:一个指标一旦变成优化目标,它就不再是个好指标。三条防线:代理只用来预警绝不进损失函数、每月重算相关性并把 r 本身监控起来、留一份随机流量做干净对照。📏先量你的标签延迟:真实退货场景 P50 只有 2.1 天,但 P95 是 19.7 天、6.8% 永远不来 —— 按"7天后统计准确率"只覆盖 80% 样本,而漏掉的那 20% 系统性偏慢,算出来的准确率有乐观偏差。哨兵对比要用排序相关性(尺度不同)且和历史基线比;它只能缩小搜索空间,不能直接回答是谁坏了。五个坑:代理进了损失函数、只抽不确定样本、按"已到达标签"算指标(乐观偏差)、💀哨兵也跟着重训(参照系失效——哨兵的价值来自它不变)、标注规范没写下来。
下一节 👉 08-告警为什么没人看.md