4. 群体稳定性指标(PSI)原理
群体稳定性指标(Population Stability Index,PSI)是风控模型监控中最核心的量化指标,用于衡量模型评分或特征分布在时间维度上的偏移程度。当PSI超过阈值时,说明模型所依赖的客群结构或数据分布已发生显著变化,模型可能失效。
4.1 PSI的数学定义
PSI基于信息论中的相对熵(KL散度)思想,衡量两个概率分布之间的差异。在风控场景中,通常比较期望分布(基准分布)与实际分布(当前分布)的差异。
设基准分布为 \( P = \{p_1, p_2, ..., p_n\} \),当前分布为 \( Q = \{q_1, q_2, ..., q_n\} \),其中 \( \sum p_i = 1 \),\( \sum q_i = 1 \)。PSI的计算公式为:
PSI = Σ ( (q_i - p_i) * ln(q_i / p_i) ) (i = 1, 2, ..., n)
其中:
- p_i:第 i 个分箱中基准样本的占比
- q_i:第 i 个分箱中当前样本的占比
- n:分箱总数
关键理解:PSI本质上是对称化的KL散度。当两个分布完全一致时,PSI = 0;差异越大,PSI值越高。风控行业通常以0.1、0.25作为预警和告警阈值。
4.2 计算公式推导
PSI的推导可以从KL散度出发。KL散度衡量分布Q相对于分布P的信息损失:
KL(P || Q) = Σ p_i * ln(p_i / q_i)
由于KL散度不对称(KL(P||Q) ≠ KL(Q||P)),PSI采用对称化处理:
PSI = KL(P || Q) + KL(Q || P)
= Σ p_i * ln(p_i / q_i) + Σ q_i * ln(q_i / p_i)
= Σ (p_i - q_i) * ln(p_i / q_i)
= Σ (q_i - p_i) * ln(q_i / p_i) // 等价形式
这种对称化使得PSI对两个方向的偏移都敏感,更适合监控模型稳定性的双向变化。
| 指标 | 公式 | 对称性 | 取值范围 |
|---|---|---|---|
| KL散度 | Σ p_i * ln(p_i / q_i) | 非对称 | [0, +∞) |
| PSI | Σ (q_i - p_i) * ln(q_i / p_i) | 对称 | [0, +∞) |
| JS散度 | 0.5 * KL(P||M) + 0.5 * KL(Q||M) | 对称 | [0, ln2] |
4.3 分箱方法
PSI的计算依赖于对连续变量进行分箱(Binning)。分箱方式直接影响PSI的敏感度和稳定性。三种主流分箱方法对比如下:
| 分箱方法 | 原理 | 优点 | 缺点 | 适用场景 |
|---|---|---|---|---|
| 等距分箱 | 将数值范围等分成k个区间,每个区间宽度相同 | 实现简单,区间边界固定 | 数据稀疏时部分箱可能为空 | 评分卡分数、标准化指标 |
| 等频分箱 | 使每个箱包含相同数量的样本 | 每个箱都有足够样本,统计稳定 | 边界随分布变化,跨期可比性差 | 特征分布监控、样本量充足时 |
| 分位数分箱 | 基于指定分位数(如十分位、二十分位)切分 | 边界具有统计意义,分布适配好 | 分位数选择依赖经验 | 模型分数监控、长期趋势分析 |
实践建议:风控模型监控中,分位数分箱(通常10~20箱)是最常用的方法。基准期使用分位数确定边界,后续各期沿用相同边界计算占比,保证跨期可比性。
4.4 PSI计算流程与分箱策略选择
下图展示了PSI计算的完整流程,以及不同分箱策略在流程中的位置:
4.5 分箱方法详解与代码实现
以下给出三种分箱方法的Python实现,以及PSI计算的完整代码:
import numpy as np
import pandas as pd
def psi_equidistant(actual, expected, bins=10):
"""等距分箱计算PSI"""
min_val = min(np.min(actual), np.min(expected))
max_val = max(np.max(actual), np.max(expected))
bin_edges = np.linspace(min_val, max_val, bins + 1)
return _psi_from_edges(actual, expected, bin_edges)
def psi_equifreq(actual, expected, bins=10):
"""等频分箱计算PSI(基于基准分布)"""
bin_edges = np.percentile(expected, np.linspace(0, 100, bins + 1))
return _psi_from_edges(actual, expected, bin_edges)
def psi_quantile(actual, expected, quantiles=[0, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1.0]):
"""分位数分箱计算PSI"""
bin_edges = np.quantile(expected, quantiles)
return _psi_from_edges(actual, expected, bin_edges)
def _psi_from_edges(actual, expected, bin_edges):
"""根据分箱边界计算PSI"""
actual_bins = np.histogram(actual, bins=bin_edges)[0]
expected_bins = np.histogram(expected, bins=bin_edges)[0]
actual_pct = actual_bins / len(actual)
expected_pct = expected_bins / len(expected)
# 避免除零和ln(0)
actual_pct = np.clip(actual_pct, 1e-10, 1)
expected_pct = np.clip(expected_pct, 1e-10, 1)
psi = np.sum((actual_pct - expected_pct) * np.log(actual_pct / expected_pct))
return psi
避坑提示:分箱时需注意边界处理。等频分箱的边界由基准期决定,后续各期沿用相同边界;若当前期数据超出基准期范围,需将超出部分归入首箱或末箱,避免出现空箱导致计算异常。
4.6 分箱方法对比总结
| 对比维度 | 等距分箱 | 等频分箱 | 分位数分箱 |
|---|---|---|---|
| 边界确定依据 | 数值范围等分 | 样本量等分 | 统计分位数 |
| 跨期可比性 | 高(边界固定) | 低(边界随分布变化) | 中(边界由基准期固定) |
| 对异常值敏感度 | 高 | 低 | 中 |
| 空箱风险 | 高(数据稀疏时) | 低 | 中 |
| 风控推荐度 | ★★☆☆☆ | ★★★☆☆ | ★★★★★ |
在实际风控监控中,分位数分箱(通常采用十分位或二十分位)是行业最佳实践。它兼顾了统计稳定性和跨期可比性,且分位数边界具有明确的业务解释意义(如“评分最低的10%客群”),便于与业务团队沟通模型偏移的具体位置。