4. PSI指标深度解析

群体稳定性指标(Population Stability Index,PSI)是授信决策引擎批次偏移诊断中最核心的量化工具。它衡量的是模型评分或关键特征在时间维度上的分布偏移程度。本章将从计算公式、分箱策略、阈值设定到拒绝样本的特殊陷阱,进行完整的技术拆解。

4.1 PSI计算公式与数学原理

PSI 基于信息论中的 KL 散度(Kullback-Leibler divergence)对称化改造,其标准计算公式如下:

PSI = Σ (P_actual_i - P_expected_i) * ln(P_actual_i / P_expected_i)

其中:
- P_expected_i:第 i 个分箱中,基准样本(如建模样本)的占比
- P_actual_i:第 i 个分箱中,实际样本(如当前申请批次)的占比
- i = 1, 2, ..., n(n 为分箱总数)

当某个分箱中 P_expected_i 或 P_actual_i 为 0 时,通常采用以下平滑处理:

if P == 0:
    P = 0.0001  # 极小正数,避免 ln(0) 或除零错误
关键理解: PSI 本质是两阶段分布的加权差异度量。每个分箱的贡献 = (实际占比 - 基准占比) × 对数比率。当两个分布完全一致时,PSI = 0;差异越大,PSI 值越高。
PSI 计算流程与分箱逻辑 基准分布 实际分布 等频分箱 等频分箱 P_expected_i P_actual_i 逐箱计算贡献值 Σ (P_actual - P_expected) × ln(P_actual / P_expected) PSI 指标值

4.2 分箱策略:等频 vs 等距 vs 自定义

分箱方式直接影响 PSI 的敏感度和稳定性。以下是三种主流策略的对比:

分箱策略 方法描述 适用场景 注意事项
等频分箱 每个分箱包含相同数量的样本(如 10 箱,每箱 10%) 模型评分、概率输出等连续变量 基准分布和实际分布的分箱边界需保持一致
等距分箱 按数值区间等宽划分(如 0-100, 100-200) 特征值分布均匀的场景 容易产生空箱,需做合并处理
自定义分箱 基于业务规则或风险等级划分 拒绝推断、特定阈值监控 需保证分箱在时间维度上语义一致
推荐实践: 在授信决策引擎中,对模型评分(如 0-1000 分)建议使用 等频分箱(10 箱)。这能保证每个分箱都有足够的样本量,避免因样本稀疏导致的 PSI 波动。

4.3 阈值设定:0.1 / 0.2 / 0.25 的行业标准

PSI 阈值是触发偏移告警的关键参数。以下是行业通用的三层阈值体系:

PSI 范围 偏移等级 建议动作
PSI < 0.1 无显著偏移 无需干预,持续监控
0.1 ≤ PSI < 0.2 轻度偏移 触发预警,排查特征或客群变化
0.2 ≤ PSI < 0.25 中度偏移 启动详细诊断,评估模型是否需要调整
PSI ≥ 0.25 严重偏移 立即暂停模型使用,启动重训练或回退
阈值调整原则: 阈值并非一成不变。对于高价值客群或监管敏感场景,可适当收紧至 0.1 即触发深度排查;对于样本量较小的场景,可放宽至 0.25 以避免误报。关键是要建立阈值与业务影响之间的映射关系。

4.4 授信决策场景中的特殊注意事项

4.4.1 拒绝样本的 PSI 计算陷阱

这是授信场景中最容易被忽视的问题。拒绝样本(Reject Samples)的 PSI 计算存在以下陷阱:

  • 样本选择偏差: 拒绝样本的评分分布天然偏向低分段,直接将其纳入 PSI 计算会人为放大偏移程度。
  • 标签缺失: 拒绝样本没有真实违约标签,无法验证模型区分度,PSI 只能反映分布变化,不能反映性能变化。
  • 分箱边界漂移: 拒绝样本的加入可能改变分箱边界,导致基准分布和实际分布的分箱语义不一致。
正确做法: 在计算 PSI 时,应区分"通过样本"和"拒绝样本"两个维度分别计算。对于拒绝样本,建议使用 拒绝推断(Reject Inference) 后的校正分布,而非原始分布。

4.4.2 时间窗口对齐

基准分布和实际分布的时间窗口必须对齐。常见问题包括:

  • 季节性偏移: 将 1 月的基准分布与 7 月的实际分布对比,可能因季节性因素产生误报。
  • 节假日效应: 节假日期间的申请客群结构与非节假日存在显著差异。

建议采用 滚动窗口对比 策略:基准窗口 = 最近 3 个月,实际窗口 = 最近 1 周,每周滚动更新。

4.4.3 多维度 PSI 监控体系

单一维度的 PSI 不足以全面反映偏移情况。建议建立以下多维监控体系:

监控维度 计算对象 告警阈值
模型评分 PSI 模型输出的最终评分 0.1
关键特征 PSI 收入、年龄、负债率等 0.15
拒绝率 PSI 拒绝样本占比的分布 0.2
通过样本 PSI 仅通过审批的样本 0.1
多维 PSI 监控体系架构 PSI 监控中心 告警聚合与决策 模型评分 PSI 阈值: 0.1 关键特征 PSI 阈值: 0.15 拒绝率 PSI 阈值: 0.2 通过样本 PSI 阈值: 0.1

4.5 实战案例:PSI 误判与纠正

场景: 某消费金融公司发现模型评分 PSI 从 0.08 骤升至 0.35,触发严重告警。初步排查发现,拒绝样本占比从 15% 上升至 40%。

错误做法: 直接将所有样本(含拒绝样本)纳入 PSI 计算,得出 PSI = 0.35,判定模型失效。

正确做法:

  1. 分别计算通过样本 PSI = 0.09(无显著偏移)和拒绝样本 PSI = 0.42(严重偏移)。
  2. 进一步分析发现,拒绝样本增加是由于风控策略收紧,而非模型评分偏移。
  3. 结论:模型本身未偏移,但策略变化导致拒绝样本分布改变。PSI 告警应归因于策略偏移,而非模型偏移。
核心教训: 在授信决策引擎中,PSI 必须结合业务上下文解读。拒绝样本的 PSI 升高不一定是模型问题,可能是策略、客群或外部环境变化所致。始终要问:PSI 在告诉我是"什么变了"?

4.6 PSI 计算代码示例(Python)

import numpy as np
import pandas as pd

def calculate_psi(expected, actual, bins=10):
    """
    计算群体稳定性指标 (PSI)
    
    Parameters:
    - expected: 基准样本的评分或特征值
    - actual: 实际样本的评分或特征值
    - bins: 分箱数量(等频分箱)
    
    Returns:
    - psi: PSI 值
    - bin_details: 每个分箱的详细信息
    """
    # 基于基准样本确定分箱边界(等频)
    percentiles = np.linspace(0, 100, bins + 1)
    bin_edges = np.percentile(expected, percentiles)
    bin_edges[0] = -np.inf
    bin_edges[-1] = np.inf
    
    # 统计每个分箱的样本占比
    expected_counts, _ = np.histogram(expected, bins=bin_edges)
    actual_counts, _ = np.histogram(actual, bins=bin_edges)
    
    expected_pct = expected_counts / len(expected)
    actual_pct = actual_counts / len(actual)
    
    # 平滑处理:避免 ln(0) 或除零
    epsilon = 0.0001
    expected_pct = np.clip(expected_pct, epsilon, 1 - epsilon)
    actual_pct = np.clip(actual_pct, epsilon, 1 - epsilon)
    
    # 计算 PSI
    psi = np.sum((actual_pct - expected_pct) * np.log(actual_pct / expected_pct))
    
    # 构建分箱详情
    bin_details = pd.DataFrame({
        'bin': range(1, bins + 1),
        'expected_pct': expected_pct,
        'actual_pct': actual_pct,
        'contribution': (actual_pct - expected_pct) * np.log(actual_pct / expected_pct)
    })
    
    return psi, bin_details

# 使用示例
expected_scores = np.random.normal(600, 100, 10000)
actual_scores = np.random.normal(620, 110, 10000)
psi_value, details = calculate_psi(expected_scores, actual_scores, bins=10)
print(f"PSI: {psi_value:.4f}")
print(details.head())
工程化建议: 在生产环境中,建议将 PSI 计算封装为微服务,支持实时流式计算和离线批量计算两种模式。同时,建立 PSI 历史趋势库,用于识别渐进式偏移和突发性偏移。