1. 课程导入

课程导入 学习卡片

在实时风控系统中,模型效果往往不取决于算法本身,而取决于特征是否“按时、完整、可信”地到达。很多线上事故并非模型突然失效,而是特征在某个时间窗口内出现缺失、延迟或陈旧,导致评分偏移、策略误杀或漏放。本课程聚焦两个高频却常被忽视的问题:特征缺失异常与特征新鲜度治理。前者关注“值有没有、对不对”,后者关注“值是不是最新的、是否在可接受的时间范围内”。二者共同决定了风控决策的稳定性与可解释性。

学习目标

完成本课程后,你应能够独立完成以下任务:

  • 识别风控特征缺失的典型模式:整列缺失、稀疏缺失、时间窗口缺失、维度对齐缺失。
  • 区分“数据源故障”“计算链路延迟”“特征回填错误”“上游口径变更”四类根因。
  • 设计新鲜度指标:事件时间、处理时间、特征年龄、端到端延迟、水位线。
  • 搭建缺失与新鲜度的监控、告警、降级与自愈闭环。
  • 在离线回放与线上灰度中验证治理策略,避免“修了监控、坏了策略”。

核心概念:缺失不是空值,新鲜度不是时间戳

在风控语境中,缺失至少包含三层含义:物理缺失(字段不存在)、逻辑缺失(字段存在但语义为空)、业务缺失(值存在但不可用,如全为默认值)。如果只把 null 当作缺失,就会漏掉“全零填充”“默认分桶”“过期缓存”等隐性缺失。新鲜度同样不只是“有没有时间戳”,而是特征值所代表的事件时间与当前决策时间之间的差距,以及该差距是否超过业务容忍阈值。

关键公式:特征年龄 = 决策时刻 − 特征事件时间;端到端延迟 = 特征可查询时刻 − 特征事件时间。前者决定“是否过期”,后者决定“是否来得及”。

为了统一语言,本课程约定以下术语:

术语含义典型阈值示例
事件时间业务事件真实发生的时间交易创建时间
处理时间特征计算完成并可被查询的时间Flink 算子输出时间
特征年龄决策时刻与事件时间之差≤ 5 分钟
缺失率缺失记录数 / 总记录数≤ 0.1%
水位线允许迟到数据的最大边界2 分钟

整体框架:从发现到自愈的四层治理

本课程将治理体系拆为四层,层层递进:

  1. 感知层:采集缺失率、特征年龄、延迟分位数、维度覆盖率,形成特征健康画像。
  2. 诊断层:通过血缘、日志、对比基线定位根因,区分偶发与系统性异常。
  3. 决策层:根据严重程度选择告警、降级、切换备用特征或拒绝决策。
  4. 自愈层:自动回填、重跑、熔断与恢复验证,形成闭环。

治理不是“把缺失率降到零”,而是在可接受的成本下,让系统在异常时仍能做出可控决策。零缺失往往意味着过度保守或过度补数,反而引入新风险。

案例场景:一次“全零特征”引发的误杀

某支付风控系统在凌晨批量任务延迟后,实时特征服务返回了全零向量。模型将全零解释为“低风险”,导致一批高风险交易被放行。事后复盘发现:缺失监控只统计了 null,未统计默认值;新鲜度监控只看了时间戳,未看事件时间。修复方案包括:增加默认值占比监控、引入特征年龄告警、在特征不可用时切换至保守策略。

# 特征健康检查伪代码
def check_feature_health(feature, now):
    missing_rate = count_null(feature) / total
    default_rate = count_default(feature) / total
    age = now - feature.event_time
    if missing_rate > 0.001 or default_rate > 0.05:
        return "DEGRADE"
    if age > timedelta(minutes=5):
        return "STALE"
    return "OK"

常见误区与复盘要点

  • 误区一:只监控离线表,不监控线上特征服务。离线正常不代表线上正常。
  • 误区二:把新鲜度等同于“最近更新时间”。缓存刷新时间不等于事件时间。
  • 误区三:缺失时统一填 0。填 0 会改变模型输入分布,可能比缺失更危险。
  • 误区四:告警阈值一刀切。不同特征对时效敏感度不同,应分级治理。

复盘时务必回答三个问题:异常何时开始?影响哪些决策?如果再次发生,系统能否在 1 分钟内自动降级?答不上来,说明治理闭环尚未形成。

实战价值