因子研究PSI监控与告警优化实战教程 - 第1节

1.1 PSI 的定义与数学原理

群体稳定性指标(Population Stability Index, PSI)是衡量两个样本分布之间差异程度的统计量。在风控因子监控中,PSI 用于量化同一因子在建模样本与监控样本之间的分布偏移程度,是判断因子是否发生“客群漂移”的核心指标。

1.1.1 数学定义

PSI 基于信息论中的 KL 散度(Kullback-Leibler Divergence) 对称化改进而来。其计算公式为:

PSI = Σ (P_i - Q_i) × ln(P_i / Q_i)

其中:

  • P_i:监控样本在第 i 个分箱中的占比(实际分布)
  • Q_i:建模样本在第 i 个分箱中的占比(基准分布)
  • ln(P_i / Q_i):自然对数比率,衡量两个分布在该分箱上的差异
  • Σ:对所有分箱求和,得到整体偏移量
💡 直观理解:PSI 可以看作“每个分箱上实际占比与基准占比的差异”乘以“差异的权重(对数比率)”的总和。当两个分布完全一致时,每个分箱的 P_i = Q_i,ln(P_i/Q_i) = 0,PSI = 0。

1.1.2 分箱规则

PSI 计算依赖分箱策略,常见分箱方式如下:

分箱方式 说明 适用场景
等距分箱 按数值范围等分成 N 段(如 0-10, 10-20, …) 因子分布均匀,无极端值
等频分箱 按样本量等分成 N 段,每段样本数相同 因子分布偏态,需保证每箱有足够样本
自定义分箱 按业务经验或模型分箱点划分 已有成熟分箱策略,需保持一致性
⚠️ 分箱注意事项:分箱数通常取 10-20 箱。分箱过少会丢失分布细节,分箱过多会导致部分分箱样本量为 0,使 ln(P_i/Q_i) 无法计算。建议监控样本中每箱至少包含 30 个样本。

1.2 PSI 在风控因子监控中的核心价值

在风控模型的生命周期中,因子分布偏移是模型失效的最常见原因之一。PSI 监控的核心价值体现在以下三个层面:

1.2.1 早期预警:发现客群漂移

当宏观经济、政策环境、获客渠道或用户行为发生变化时,因子的分布会随之偏移。PSI 能够量化这种偏移程度,在模型效果明显下降之前发出预警。例如:

  • 收入因子:疫情期间收入分布整体左移,PSI 从 0.02 升至 0.15
  • 年龄因子:新渠道引入年轻客群,年龄分布右移,PSI 突破 0.10 阈值
  • 负债率因子:利率调整后用户负债行为变化,PSI 持续上升

1.2.2 量化评估:辅助模型迭代决策

PSI 提供了一个统一的量化标准,帮助风控团队判断是否需要重新训练模型或调整分箱策略:

PSI 范围 偏移程度 建议行动
0.00 - 0.05 无显著偏移 持续监控,无需干预
0.05 - 0.10 轻度偏移 加强监控频率,排查原因
0.10 - 0.25 中度偏移 启动模型评估,考虑分箱调整
> 0.25 严重偏移 立即重新训练模型或回退备用模型

1.2.3 归因分析:定位偏移源头

PSI 不仅给出整体偏移量,还能通过分箱贡献度定位具体哪些取值区间发生了显著变化。例如,某因子 PSI 为 0.18,其中“30-40 岁”分箱贡献了 60% 的偏移量,说明该年龄段客群发生了明显变化。

📌 核心价值总结:PSI 是风控因子监控的“仪表盘”——它告诉你分布是否偏移、偏移多大、偏移在哪,为模型稳定性管理提供数据驱动的决策依据。

1.3 PSI 计算流程与示例

下面通过一个完整示例演示 PSI 的计算过程。假设某风控因子“月收入”在建模样本和监控样本中的分布如下:

1.3.1 分箱与占比计算

分箱区间(元) 建模样本 Q_i 监控样本 P_i P_i - Q_i ln(P_i/Q_i) 分箱贡献
0 - 5000 0.20 0.25 0.05 0.2231 0.0112
5000 - 10000 0.35 0.30 -0.05 -0.1542 0.0077
10000 - 20000 0.30 0.28 -0.02 -0.0690 0.0014
20000 - 50000 0.12 0.14 0.02 0.1542 0.0031
> 50000 0.03 0.03 0.00 0.0000 0.0000
PSI = Σ 分箱贡献 0.0234

计算得到 PSI = 0.0234,小于 0.05,说明该因子在监控期间分布稳定,无需干预。

1.4 PSI 监控的完整流程

下图展示了 PSI 监控从数据采集到告警触发的完整链路:

PSI 监控完整流程图 数据采集 分箱处理 PSI 计算 阈值判断 正常监控 告警触发 归因分析 PSI ≤ 0.05 PSI > 0.05 反馈优化(分箱调整/模型迭代)

1.5 PSI 与其他稳定性指标的对比

在风控实践中,除了 PSI,还有几种常用的稳定性指标。下表对比了它们的核心差异:

指标 衡量对象 取值范围 对极端值敏感度 主要用途
PSI 因子分布偏移 [0, +∞) 中等 因子级稳定性监控
CSI 模型分数偏移 [0, +∞) 中等 模型级稳定性监控
KS 好坏样本区分度 [0, 1] 高 模型区分能力评估
IV 因子预测能力 [0, +∞) 高 因子筛选与分箱评估
🔑 关键区别:PSI 关注的是“分布是否变了”,KS 关注的是“好坏是否分得开”,IV 关注的是“这个因子有没有用”。三者共同构成风控模型监控的“铁三角”。

1.6 PSI 计算的 Python 实现

下面给出一个完整的 PSI 计算函数,可直接用于生产环境:

import numpy as np
import pandas as pd

def calculate_psi(actual, expected, bins=10, bin_type='equal_freq'):
    """
    计算群体稳定性指标 (PSI)
    
    Parameters:
    -----------
    actual : array-like
        监控样本(实际分布)
    expected : array-like
        建模样本(基准分布)
    bins : int
        分箱数量,默认 10
    bin_type : str
        分箱方式:'equal_freq'(等频)或 'equal_width'(等距)
    
    Returns:
    --------
    psi : float
        PSI 值
    breakdown : DataFrame
        每个分箱的详细贡献
    """
    # 1. 基于基准分布确定分箱边界
    if bin_type == 'equal_freq':
        # 等频分箱:按基准分布的分位数划分
        percentiles = np.linspace(0, 100, bins + 1)
        bin_edges = np.percentile(expected, percentiles)
    else:
        # 等距分箱:按基准分布的最小最大值等距划分
        bin_edges = np.linspace(np.min(expected), np.max(expected), bins + 1)
    
    # 2. 对两个样本进行分箱
    actual_bins = np.digitize(actual, bin_edges, right=True)
    expected_bins = np.digitize(expected, bin_edges, right=True)
    
    # 3. 计算每个分箱的占比
    actual_counts = np.bincount(actual_bins, minlength=bins + 1)[1:bins + 1]
    expected_counts = np.bincount(expected_bins, minlength=bins + 1)[1:bins + 1]
    
    actual_pct = actual_counts / len(actual)
    expected_pct = expected_counts / len(expected)
    
    # 4. 处理零值:用极小值替代,避免 ln(0)
    epsilon = 1e-6
    actual_pct = np.clip(actual_pct, epsilon, 1.0)
    expected_pct = np.clip(expected_pct, epsilon, 1.0)
    
    # 5. 计算 PSI
    psi_value = np.sum((actual_pct - expected_pct) * np.log(actual_pct / expected_pct))
    
    # 6. 构建详细分解表
    breakdown = pd.DataFrame({
        'bin_start': bin_edges[:-1],
        'bin_end': bin_edges[1:],
        'expected_pct': expected_pct,
        'actual_pct': actual_pct,
        'contribution': (actual_pct - expected_pct) * np.log(actual_pct / expected_pct)
    })
    
    return psi_value, breakdown

# 使用示例
np.random.seed(42)
expected_data = np.random.normal(5000, 1500, 10000)  # 建模样本
actual_data = np.random.normal(5200, 1600, 10000)    # 监控样本

psi, breakdown = calculate_psi(actual_data, expected_data, bins=10)
print(f"PSI = {psi:.4f}")
print(f"偏移程度:{'稳定' if psi <= 0.05 else '轻度偏移' if psi <= 0.10 else '中度偏移' if psi <= 0.25 else '严重偏移'}")
💡 代码要点:
  • 使用 np.digitize 进行高效分箱,避免循环
  • 通过 np.clip 处理零值,防止 ln(0) 报错
  • 返回详细分解表,便于定位偏移源头
  • 支持等频和等距两种分箱方式,适应不同场景

1.7 本章小结

PSI 作为风控因子监控的核心指标,其价值在于:

  • 数学上:基于 KL 散度对称化,量化两个分布的差异
  • 业务上:提供早期预警、量化评估、归因分析三大能力
  • 实践上:通过分箱策略和阈值判断,形成完整的监控闭环