🏠 总目录📚 本教程 07 · 没标签怎么发现退化
📑 本页目录(点开跳转)

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探索 随机放行 = 探索的风控版

✅ 检查点

  1. 标签延迟为什么是个严重问题?用信贷的例子说明。
  2. 欺诈场景的标签有什么比"延迟"更深的问题?
  3. 五种代理信号是什么?按什么排序的?
  4. 行为代理的正确用法是什么?哪一步不能省?为什么?
  5. 「冠军-挑战者」为什么值得做?
  6. 人工抽样为什么必须随机抽?分层抽样怎么省钱?
  7. 为什么早期信号不该接自动回滚?
  8. 什么是拒绝推断?唯一能拿到干净数据的办法是什么?
  9. 「完播率」那个事故里发生了什么?它是什么定律的案例?三条防线是什么?
  10. 量标签延迟时,为什么要看 P95 而不只是中位数?「按 7 天统计准确率」会有什么偏差?
  11. 冠军-挑战者的差异为什么要用排序相关性而不是绝对差值?这个信号能回答"是谁坏了"吗?
  12. 标签延迟超过一个月时,主力手段应该是什么?
  13. 为什么哨兵模型不能跟着重训?
👀 答案
  1. 因为你今天发现的问题是延迟那么久之前就开始的。信贷延迟 3 个月 → 这 3 个月里放出去的所有贷款都已经是坏决策了。
  2. 很多标签永远不会来——没被发现的欺诈在数据里就是"正常交易",标签本身就是有偏的
  3. ①特征分布漂移 ②预测分布变化 ③行为侧即时反应 ④模型间一致性 ⑤人工抽样。按有多接近真实指标排序。
  4. 用法是用历史数据算出代理和真实标签的相关性,只要相关性稳定就能做早期预警不能省的是最后一步:真实标签到了之后回头验证代理是否还可靠——因为代理和标签的关系本身也会漂移
  5. 因为简单模型不容易坏,可以当参照系;它效果不如主模型,但稳定性是主模型的参照系。成本极低(逻辑回归几乎不占资源)。
  6. 必须随机抽是因为只抽模型不确定的会高估错误率。分层抽样:按置信度分层,高置信层少抽、低置信层多抽,再按占比加权还原——同样预算精度更高
  7. 因为越早的信号越不准、可能误报;接成自动回滚会因频繁误报而被关掉。早期信号应该触发调查而不是自动动作。
  8. 风控拒绝了一笔贷款 → 它没发生 → 永远不知道会不会违约,训练数据里只有被通过的人。唯一能拿到干净数据的办法是随机放行一小部分(付出真实损失换无偏标签)。
  9. 完播率被选为次日留存的代理(r=0.61),但模型开始优化它之后,短视频占比从 31% 涨到 68%,完播率 42%→54% 而次日留存 38.5%→37.3%,相关性掉到 0.08。这是 Goodhart 定律一个指标一旦变成优化目标,它就不再是个好指标——代理能当代理是因为"在原来的策略下"相关,而模型改变了策略本身。三条防线:①代理只用来预警,绝不进损失函数/排序公式定期重算相关性并把 r 本身监控起来留一份不受模型影响的随机流量做干净对照
  10. 因为尾巴比想象长得多(真实例子:P50 只有 2.1 天,但 P95 是 19.7 天、P99 是 58.3 天,还有 6.8% 永远不来)。按 7 天统计只覆盖约 80% 的样本,而漏掉的 20% 系统性偏向慢退货 → 算出来的准确率有乐观偏差
  11. 因为两个模型的分数尺度本来就不同,绝对差值没有可比性;而且要和历史基线比,不是和 1.0 比。它回答不了"是谁坏了"——但它能把范围从"整个系统"缩小到"这两个模型之一"。哨兵的价值是缩小搜索空间,不是直接给答案。
  12. 随机放行 / 随机流量 + 早期代理,且全部辅助手段都要上。绝不能只靠真实标签做决策——等它到齐时损失早已发生。
  13. 因为哨兵的价值来自"它不变"。一旦跟着定期重训,它就和主模型一起漂走了,参照系就没了。应该长期冻结,只在明确的时点更新。

🛑 可以停在这里

走神救援

⭐⭐教科书假设你知道对错,现实里常常不知道:退货等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

打卡记录保存在你的浏览器里,首页能看到总进度