2. PSI 数学原理与公式推导
群体稳定性指标(Population Stability Index, PSI)是衡量两个分布之间差异程度的统计量。在风控场景中,它用于量化特征在期望分布(通常为建模样本或基准期)与实际分布(通常为线上实时样本或监控期)之间的偏移程度。理解 PSI 的数学原理是正确应用该指标的前提。
2.1 PSI 的数学定义
PSI 的核心思想来源于信息论中的 KL 散度(Kullback-Leibler Divergence),但 PSI 是对称化的版本。其数学定义如下:
PSI = Σ ( (实际占比_i - 期望占比_i) * ln(实际占比_i / 期望占比_i) )
其中:
- 实际占比_i:第 i 个分箱中,实际样本数量占该期总样本数的比例。
- 期望占比_i:第 i 个分箱中,期望样本数量占该期总样本数的比例。
- ln:自然对数。
- Σ:对所有分箱求和。
关键理解: PSI 本质上衡量的是两个概率分布之间的“距离”。当两个分布完全一致时,每个分箱的 (实际占比_i / 期望占比_i) = 1,ln(1) = 0,因此 PSI = 0。PSI 值越大,表示分布偏移越严重。
2.2 期望分布与实际分布
在风控特征监控中,两个分布的定义如下:
| 分布类型 | 定义 | 常见来源 | 用途 |
|---|---|---|---|
| 期望分布 | 模型开发或验证时使用的基准分布 | 训练集、OOT 测试集、模型上线前一个月的样本 | 作为“正常”或“预期”状态的参照 |
| 实际分布 | 当前监控周期内线上实时样本的分布 | 最近一天、一周或一个月的线上流量 | 检测当前特征是否发生偏移 |
PSI 计算的核心假设是:如果特征分布稳定,那么实际分布应与期望分布保持一致。任何显著偏离都意味着数据分布发生了结构性变化,可能导致模型预测能力下降。
2.3 分箱与概率计算
PSI 的计算依赖于对连续特征进行分箱(Binning)。分箱的目的是将连续值离散化,从而计算每个区间内的样本占比。常用的分箱方法包括:
- 等距分箱:将特征值范围均匀划分为 N 个区间。
- 等频分箱:使每个区间包含大致相同数量的样本。
- 自定义分箱:基于业务经验或模型分箱结果(如决策树节点)划分。
分箱完成后,计算每个箱子的占比:
占比_i = 该箱样本数 / 总样本数
为避免 ln(0) 或除以 0 的情况,通常对占比进行微小平滑处理(如加 0.0001)。
分箱注意事项:
- 期望分布和实际分布必须使用相同的分箱边界。
- 分箱数量通常建议在 5~20 之间。过少会丢失细节,过多会导致噪声放大。
- 对于类别特征,每个类别天然就是一个分箱。
2.4 PSI 阈值与业务解读
PSI 的计算结果是一个非负实数。在实际风控应用中,通常根据经验设定阈值来判断特征稳定性的等级。以下是业界通用的 PSI 阈值解读标准:
| PSI 值范围 | 稳定性等级 | 业务解读 | 建议行动 |
|---|---|---|---|
| PSI < 0.1 | 稳定 | 特征分布无显著变化,模型可信度高 | 无需干预,继续常规监控 |
| 0.1 ≤ PSI < 0.25 | 轻度偏移 | 特征分布发生轻微变化,需关注趋势 | 加强监控频率,排查可能的原因 |
| PSI ≥ 0.25 | 严重偏移 | 特征分布发生显著变化,模型可能失效 | 立即告警,启动模型重训或特征重构流程 |
重要提醒: 阈值并非绝对标准,需结合业务场景调整。例如:
- 在高客单价场景(如大额信贷),可适当降低阈值(如 0.15 即告警)。
- 在高流量场景(如支付风控),可适当提高阈值以减少误报。
- 对于新上线的特征,建议先积累 1~2 周数据建立基准分布,再启用 PSI 监控。
2.5 PSI 的数学性质与局限
理解 PSI 的数学性质有助于更准确地解读计算结果:
- 非对称性:虽然 PSI 公式本身是对称的(交换期望和实际结果相同),但在业务解读中,期望分布是固定的基准,实际分布是动态监控对象,因此方向性很重要。
- 对零占比敏感:如果某个分箱在期望分布中占比为 0,而在实际分布中占比非 0,会导致 ln(∞) 问题。因此必须进行平滑处理。
- 分箱数量影响:分箱越多,PSI 值通常越大(因为噪声被放大)。建议在相同分箱策略下进行纵向对比。
- 无法区分偏移方向:PSI 只衡量差异大小,不指示偏移方向(如均值升高还是降低)。需要结合特征统计量(如均值、标准差)进一步分析。
2.6 计算示例
假设某特征“近 30 天借款次数”在期望分布和实际分布中分箱后的占比数据如下:
| 分箱区间 | 期望占比 (%) | 实际占比 (%) | 差值 | 比值对数 | 单项 PSI |
|---|---|---|---|---|---|
| [0, 1] | 40.0 | 35.0 | -5.0 | ln(35/40) = -0.1335 | 0.0067 |
| [1, 3] | 30.0 | 32.0 | 2.0 | ln(32/30) = 0.0645 | 0.0013 |
| [3, 5] | 20.0 | 22.0 | 2.0 | ln(22/20) = 0.0953 | 0.0019 |
| [5, +∞) | 10.0 | 11.0 | 1.0 | ln(11/10) = 0.0953 | 0.0010 |
| 合计 | 100.0 | 100.0 | — | — | 0.0109 |
计算得到 PSI = 0.0109 < 0.1,说明该特征分布稳定,无需干预。
代码实现提示: 在 Python 中计算 PSI 的典型代码如下:
import numpy as np
def calculate_psi(expected, actual, bins=10):
# 等频分箱
percentiles = np.percentile(expected, np.linspace(0, 100, bins + 1))
expected_bins = np.histogram(expected, bins=percentiles)[0]
actual_bins = np.histogram(actual, bins=percentiles)[0]
# 计算占比并平滑
expected_pct = expected_bins / len(expected) + 1e-6
actual_pct = actual_bins / len(actual) + 1e-6
# 计算 PSI
psi = np.sum((actual_pct - expected_pct) * np.log(actual_pct / expected_pct))
return psi