2. PSI 数学原理与计算公式

群体稳定性指标(Population Stability Index, PSI)是衡量两个分布之间差异的标准化度量。在风控建模中,它用于量化模型评分在时间维度上的偏移程度。本章从信息论基础出发,详细推导 PSI 的核心公式,并解释分箱与概率分布在计算中的关键作用。

2.1 从 KL 散度到 PSI 的数学推导

PSI 的数学根源是 Kullback-Leibler 散度(相对熵),它衡量两个概率分布 P 和 Q 之间的不对称差异。对于离散分布,KL 散度定义为:

KL(P || Q) = Σ P(i) * ln( P(i) / Q(i) )

其中 P 为实际分布(Actual),Q 为预期分布(Expected)。KL 散度不满足对称性,即 KL(P||Q) ≠ KL(Q||P)。PSI 通过引入对称化处理,将两个方向的 KL 散度相加:

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) )

最终得到 PSI 的标准计算公式:

PSI = Σ (实际占比 - 预期占比) × ln(实际占比 / 预期占比)

其中:

  • 实际占比(Actual%):当前样本(如月度评分)在各分箱中的样本比例。
  • 预期占比(Expected%):基准样本(如建模样本)在各分箱中的样本比例。
  • ln:自然对数,用于放大比例差异的非线性效应。

2.2 分箱策略与概率分布映射

PSI 计算的前提是将连续变量(如模型评分)离散化为有限个分箱(Bins)。分箱方式直接影响 PSI 的敏感性和稳定性。

分箱方式 方法描述 适用场景 注意事项
等距分箱 按评分区间等宽划分(如每 20 分一箱) 评分分布均匀时 极端值可能导致空箱
等频分箱 按样本量等比例划分(每箱约 10% 样本) 建模样本分布偏态时 分箱边界随分布变化
业务分箱 按业务阈值划分(如拒绝/通过/优质区间) 业务规则明确时 需定期验证阈值合理性
决策树分箱 基于目标变量最优切分点 需要最大化区分度时 过拟合风险较高

分箱后,每个箱子的实际占比和预期占比共同构成两个离散概率分布。PSI 本质上是在比较这两个分布之间的“距离”。

实践建议:风控建模中通常采用 10 等频分箱。若某箱在预期分布中占比为 0,可做极小值平滑处理(如 0.0001),避免 ln(0) 导致计算异常。

2.3 PSI 计算的分步流程

以下为 PSI 计算的标准化步骤,适用于模型评分或任何连续变量的稳定性监控:

  1. 确定基准分布:选取建模样本或历史稳定期的评分数据作为预期分布。
  2. 划分分箱:基于预期分布确定分箱边界(通常 10 箱)。
  3. 计算预期占比:统计每个分箱在预期样本中的比例(Expected%)。
  4. 映射实际分布:将当前样本按相同分箱边界划分,计算实际占比(Actual%)。
  5. 计算单箱贡献:对每个分箱计算 (Actual% - Expected%) × ln(Actual% / Expected%)。
  6. 求和得到 PSI:将所有分箱的贡献值相加。
常见陷阱:实际分布中出现预期分布未覆盖的分箱(即 Expected% = 0)时,必须进行平滑处理。直接丢弃该分箱会低估漂移程度。

2.4 PSI 计算示例(10 等频分箱)

下表展示了一个 10 等频分箱的 PSI 计算过程。预期分布为建模样本,实际分布为 3 个月后的评分数据。

分箱 评分区间 预期占比(%) 实际占比(%) 差值 ln(实际/预期) 单箱贡献
1 300-420 10.0 12.5 +2.5 0.2231 0.0056
2 421-480 10.0 11.0 +1.0 0.0953 0.0010
3 481-530 10.0 10.5 +0.5 0.0488 0.0002
4 531-575 10.0 10.0 0.0 0.0000 0.0000
5 576-615 10.0 9.5 -0.5 -0.0513 0.0003
6 616-650 10.0 9.0 -1.0 -0.1054 0.0011
7 651-685 10.0 8.5 -1.5 -0.1625 0.0024
8 686-720 10.0 8.0 -2.0 -0.2231 0.0045
9 721-760 10.0 7.5 -2.5 -0.2877 0.0072
10 761-850 10.0 13.5 +3.5 0.3001 0.0105
PSI 合计 0.0328

该示例中 PSI = 0.0328,对应行业通用阈值:PSI < 0.1 表示分布稳定,0.1-0.25 需关注,> 0.25 表示显著漂移。

2.5 PSI 的分布偏移可视化

下图展示了预期分布与实际分布在 10 个分箱中的占比对比,直观反映漂移方向与幅度。

PSI 分箱分布对比:预期 vs 实际 预期占比 实际占比 0% 2% 4% 6% 8% 10% 12% 14% 1 2 3 4 5 6 7 8 9 箱 1-3:实际占比上升 箱 7-9:实际占比下降 箱 10:实际占比显著上升

2.6 PSI 与信息论的关系

PSI 与信息论中的交叉熵和 KL 散度存在直接关联。下表总结了三个度量的核心差异:

度量 公式 对称性 取值范围 风控应用
KL 散度 Σ P(i) ln(P(i)/Q(i)) 非对称 [0, +∞) 单方向分布差异
交叉熵 -Σ P(i) ln Q(i) 非对称 [0, +∞) 模型损失函数
PSI Σ (P-Q) ln(P/Q) 对称 [0, +∞) 分布稳定性监控

PSI 的对称性使其成为监控模型稳定性的首选指标——它同时惩罚“实际分布相对于预期分布”的左右两侧偏移,避免单方向偏差被掩盖。

2.7 PSI 计算代码实现(Python)

以下代码展示了 PSI 的完整计算过程,包含分箱、平滑处理和结果输出:

import numpy as np
import pandas as pd

def calculate_psi(expected, actual, bins=10, smooth=0.0001):
    """
    计算群体稳定性指标 (PSI)
    
    参数:
        expected: array-like, 预期分布(建模样本评分)
        actual: array-like, 实际分布(当前样本评分)
        bins: int, 分箱数量(默认10)
        smooth: float, 平滑值,防止ln(0)
    
    返回:
        psi: float, PSI值
        bin_df: DataFrame, 各分箱明细
    """
    # 基于预期分布确定分箱边界
    percentiles = np.linspace(0, 100, bins + 1)
    bin_edges = np.percentile(expected, percentiles)
    bin_edges[0] = -np.inf
    bin_edges[-1] = np.inf
    
    # 分箱并计算占比
    expected_bins = np.digitize(expected, bin_edges[1:-1])
    actual_bins = np.digitize(actual, bin_edges[1:-1])
    
    expected_counts = np.bincount(expected_bins, minlength=bins+1)[1:bins+1]
    actual_counts = np.bincount(actual_bins, minlength=bins+1)[1:bins+1]
    
    expected_pct = expected_counts / len(expected)
    actual_pct = actual_counts / len(actual)
    
    # 平滑处理
    expected_pct = np.clip(expected_pct, smooth, 1 - smooth)
    actual_pct = np.clip(actual_pct, smooth, 1 - smooth)
    
    # 计算PSI
    psi = np.sum((actual_pct - expected_pct) * np.log(actual_pct / expected_pct))
    
    # 构建明细表
    bin_df = 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_df

# 示例用法
np.random.seed(42)
expected_scores = np.random.normal(600, 100, 10000)
actual_scores = np.random.normal(620, 110, 10000)

psi_value, psi_details = calculate_psi(expected_scores, actual_scores)
print(f"PSI = {psi_value:.4f}")
print(psi_details.head())
关键参数说明:
  • bins=10:等频分箱,每箱约 10% 样本,是风控建模的行业标准。
  • smooth=0.0001:极小值平滑,避免分箱占比为 0 时 ln(0) 报错。
  • np.percentile:基于预期分布计算分位点,保证分箱边界稳定。

2.8 PSI 的阈值判定标准

行业通用的 PSI 阈值体系如下,用于判断模型是否需要重新训练或校准:

PSI 范围 稳定性等级 建议行动
< 0.10 稳定 无需干预,持续监控
0.10 - 0.25 轻度漂移 排查特征分布变化,评估影响
0.25 - 0.50 中度漂移 启动模型校准或局部重训
> 0.50 严重漂移 立即停用模型,全面重训
阈值调整建议:对于高风险业务(如信贷审批),建议将阈值收紧至 0.15(轻度)和 0.30(严重);对于低风险业务(如营销评分),可适当放宽至 0.20 和 0.40。

2.9 PSI 与压力测试的关联基础

PSI 不仅是稳定性监控指标,更是压力测试中识别异常漂移的核心工具。在后续章节中,我们将基于 PSI 的计算结果,进一步分析:

  • 单变量 PSI 分解:定位导致整体 PSI 上升的关键分箱和特征。
  • 时间序列 PSI 趋势:监控 PSI 随时间的变化斜率,预警加速漂移。
  • 压力场景 PSI 模拟:在极端经济情景下,计算 PSI 的预期变化范围。