3. 特征缺失的定义与分类

特征缺失是风控网关在实时推理中最常见的数据质量问题。它指模型在打分时刻,某个或某些入模特征字段的值为空、无效或未生成。缺失不仅导致模型输出偏差,还会引发PSI(群体稳定性指标)的虚假波动,干扰模型监控。因此,必须从定义出发,对缺失进行系统性分类,才能制定有效的巡检与补偿策略。

3.1 特征缺失的三大分类

根据缺失产生的根因与发生模式,我们将特征缺失分为三类:系统性缺失、偶发性缺失和逻辑缺失。下表从根因、特征、影响范围三个维度进行对比:

分类 根因 特征 影响范围 典型场景
系统性缺失 上游数据源断连、接口超时、ETL任务失败 连续、成片、可预测 全量或大批量请求 三方征信接口宕机、数据库连接池耗尽
偶发性缺失 网络抖动、瞬时高并发、单次请求异常 离散、随机、低频率 个别请求 DNS解析失败、TCP重传超时
逻辑缺失 规则未命中、条件分支未执行、数据源无此字段 固定、可解释、与业务逻辑绑定 特定客群或场景 白名单用户无多头借贷记录、新客无历史还款行为
巡检要点: 系统性缺失需要立即触发告警与降级;偶发性缺失依赖重试与缓存;逻辑缺失则需在特征工程中预设默认值或哑变量。

3.2 三类缺失的详细解析

3.2.1 系统性缺失(上游断连)

系统性缺失是最严重的一类缺失,通常由基础设施故障引起。当风控网关依赖的外部数据源(如人行征信、多头借贷平台、设备指纹服务)发生断连时,所有依赖该数据源的特征都会同时缺失。这类缺失具有成片性和持续性,若不及时处理,会导致模型打分大面积失效。

  • 典型表现: 某时间段内,所有请求的“多头借贷数”字段均为空。
  • 巡检策略: 设置滑动窗口(如5分钟)内缺失率阈值,超过5%即触发P0级告警。
  • 补偿方案: 启用本地缓存特征、降级为备用模型或直接拒绝。

3.2.2 偶发性缺失(网络抖动)

偶发性缺失是网络层面的随机波动导致的数据获取失败。与系统性缺失不同,它不持续,且通常只影响极少数请求。例如,某次HTTP请求因TCP超时未返回,但下一秒重试成功。这类缺失对模型整体稳定性影响较小,但会污染单条样本的打分结果。

  • 典型表现: 日志中零星出现“特征X获取超时”,但整体缺失率低于0.1%。
  • 巡检策略: 关注单特征缺失率的日环比变化,而非绝对值。
  • 补偿方案: 网关层实现自动重试(最多3次,间隔100ms),重试失败后使用历史均值填充。

3.2.3 逻辑缺失(规则未命中)

逻辑缺失是业务规则或特征工程设计导致的“合理缺失”。例如,对于从未申请过信贷的用户,其“近3个月申请次数”字段自然为空;或者风控规则中仅对“非白名单用户”执行多头借贷查询,白名单用户该字段缺失。这类缺失不是故障,而是业务逻辑的一部分,但若模型未做特殊处理,会将其视为0或空值,导致打分偏差。

  • 典型表现: 特定客群(如新客、白名单)的某些特征长期缺失。
  • 巡检策略: 按客群分层统计缺失率,与业务规则对照验证。
  • 补偿方案: 在特征工程中为逻辑缺失设计专门的哑变量(如“是否命中查询规则”),避免模型将缺失与0混淆。

3.3 缺失对模型打分的影响

特征缺失会从三个层面影响模型打分:

  1. 特征值替代偏差: 大多数模型在推理时会将缺失值填充为0、均值或众数。若填充值与真实分布不符,会直接改变该特征的贡献权重,导致打分偏移。
  2. 特征交互失效: 树模型或深度学习模型中的特征交叉依赖缺失字段时,整个分支或神经元输出可能失效,使模型退化为低维子模型。
  3. PSI虚高: 缺失率的变化会改变特征的整体分布。例如,系统性缺失导致某特征大量为0,会使PSI计算中的实际分布与期望分布产生巨大差异,触发假阳性告警。
实战避坑: 不要将缺失直接填充为0而不做标记。0在风控特征中往往有业务含义(如“无多头借贷”),与“缺失”是两种完全不同的状态。建议使用-999、NaN或单独的特征缺失标志位。
特征缺失分类与影响关系图 特征缺失 系统性缺失 偶发性缺失 逻辑缺失 特征值替代偏差 特征交互失效 PSI虚高 巡检策略建议: 系统性缺失 → 滑动窗口缺失率告警(阈值5%) 偶发性缺失 → 单特征缺失率日环比监控 逻辑缺失 → 按客群分层统计,与业务规则对照

3.4 缺失对PSI计算的干扰机制

PSI(Population Stability Index)用于衡量特征分布随时间的变化。当特征缺失发生时,实际分布中会多出一个“缺失值”分箱(通常为0或空值),而期望分布中该分箱的占比可能极低甚至为0。这会导致PSI值急剧升高,产生假阳性告警。下表展示了缺失对PSI计算的具体影响:

分箱区间 期望分布(训练集) 实际分布(无缺失) 实际分布(有缺失) PSI贡献(无缺失) PSI贡献(有缺失)
[0, 10) 40% 42% 30% 0.001 0.029
[10, 50) 35% 34% 25% 0.000 0.033
[50, 100) 20% 19% 15% 0.001 0.014
[100, +∞) 5% 5% 4% 0.000 0.003
缺失值 0% 0% 26% 0.000 0.305
PSI合计 - - - 0.002 0.384
关键结论: 上例中,26%的缺失率使PSI从0.002(稳定)飙升至0.384(不稳定),触发告警。但实际模型分布并未变化,只是缺失干扰了分箱。因此,在PSI计算前必须对缺失值进行预处理:要么剔除缺失样本,要么将缺失单独作为一个分箱并排除其PSI贡献。
缺失对PSI计算的干扰流程 正常特征分布 PSI = 0.002 正常告警 特征缺失(26%) PSI = 0.384 假阳性告警 解决方案: 1. 在PSI计算前,剔除缺失值样本,仅对有效值进行分箱统计。 2. 若需保留缺失分箱,则将其PSI贡献置零,避免干扰整体指标。

3.5 缺失巡检的工程实现要点

在风控网关中实现特征缺失巡检,需要关注以下工程要点:

  • 实时统计: 使用滑动窗口(如1分钟/5分钟)统计每个特征的缺失率,避免全量扫描。
  • 分级告警: 系统性缺失触发P0告警(短信+电话),偶发性缺失触发P2告警(邮件+工单),逻辑缺失仅记录日志。
  • 缺失补偿: 网关层配置特征级别的填充策略,如均值填充、历史值填充、模型预测填充。
  • PSI预处理: 在PSI计算管道中,增加缺失值过滤步骤,确保分布对比不受缺失干扰。
代码示例: 特征缺失率实时统计(伪代码)
# 滑动窗口缺失率统计
class MissingRateMonitor:
    def __init__(self, window_size=300, threshold=0.05):
        self.window = deque(maxlen=window_size)
        self.threshold = threshold
    
    def record(self, feature_name, is_missing):
        self.window.append((feature_name, is_missing))
    
    def get_missing_rate(self, feature_name):
        total = sum(1 for f, _ in self.window if f == feature_name)
        missing = sum(1 for f, m in self.window if f == feature_name and m)
        return missing / total if total > 0 else 0.0
    
    def check_alert(self, feature_name):
        rate = self.get_missing_rate(feature_name)
        if rate > self.threshold:
            trigger_alert(f"Feature {feature_name} missing rate: {rate:.2%}")