3. PSI计算原理:分箱方法、比例计算与对数求和

群体稳定性指标(PSI)的核心思想是量化两个分布之间的差异。其计算过程可拆解为三个关键步骤:分箱、比例计算与对数求和。每一步的选择与实现都直接影响PSI值的敏感度和可靠性。

3.1 分箱方法:等距与等频

分箱是将连续变量或离散变量划分为若干区间(桶)的过程。PSI对分箱方式敏感,常用方法有两种:等距分箱和等频分箱。

分箱方法 定义 适用场景 注意事项
等距分箱 将变量取值范围均匀划分为N个宽度相同的区间 变量分布均匀,无极端离群点 若数据稀疏,部分箱可能样本量为0,导致计算异常
等频分箱 将变量按分位数划分,使每个区间包含大致相等的样本量 长尾分布、存在离群点、评分卡模型 需保证期望分布(训练集)分箱边界与当前分布一致
实践建议:在风控模型监控中,推荐使用等频分箱,且分箱数通常设为10(即按十分位数划分)。这能确保每个箱都有足够的样本支撑比例计算,避免因零样本导致的PSI无穷大问题。

分箱完成后,需记录每个箱的边界值。PSI计算要求期望分布(通常为训练集或基准期)与实际分布(当前监控期)使用完全相同的分箱边界。

3.2 实际分布与期望分布的比例计算

在每个箱内,分别计算两个分布的样本占比:

  • 期望占比(Expected Proportion, Ei):基准期落在第i箱的样本数 / 基准期总样本数
  • 实际占比(Actual Proportion, Ai):监控期落在第i箱的样本数 / 监控期总样本数

计算时需注意两个关键处理:

  1. 零占比处理:若Ei或Ai为0,直接代入会导致对数计算失败。通常做法是给每个箱的计数加一个极小常数(如0.5或1e-6),或将该箱与相邻箱合并。
  2. 比例归一化:确保所有箱的Ei之和为1,Ai之和为1。
核心公式:PSI = Σ[(Ai - Ei) × ln(Ai / Ei)],其中i从1到N(N为分箱总数)。

3.3 自然对数与求和:PSI的最终聚合

得到每个箱的Ei和Ai后,按以下步骤完成PSI计算:

  1. 计算比例差:(Ai - Ei)
  2. 计算比例比的自然对数:ln(Ai / Ei)
  3. 箱内乘积:将步骤1与步骤2的结果相乘
  4. 全局求和:对所有箱的乘积结果求和,得到最终PSI值

自然对数ln的作用是放大差异:当Ai与Ei接近时,ln(Ai/Ei)趋近于0;当两者偏离较大时,对数值会快速增大,使PSI对分布偏移更敏感。

常见误区:部分实现使用log10而非自然对数ln,这会导致PSI数值整体缩小约2.3倍。在设定阈值时,必须明确所使用的对数底数。行业通用标准基于自然对数ln。

3.4 PSI计算流程总览

下图展示了从原始数据到PSI值的完整计算链路:

PSI计算流程 期望分布(基准期) 实际分布(监控期) 等频分箱(N=10) 应用相同分箱边界 计算各箱期望占比 Eᵢ 计算各箱实际占比 Aᵢ Σ[(Aᵢ-Eᵢ)×ln(Aᵢ/Eᵢ)] PSI 值

3.5 计算示例与代码实现

以下是一个完整的PSI计算Python实现,包含等频分箱与零占比处理:

import numpy as np
import pandas as pd

def calculate_psi(expected, actual, bins=10):
    """
    计算群体稳定性指标(PSI)
    
    Parameters:
    expected: array-like, 期望分布(基准期数据)
    actual: array-like, 实际分布(监控期数据)
    bins: int, 分箱数量(默认10)
    
    Returns:
    float: PSI值
    """
    # 1. 基于期望分布确定分箱边界(等频分箱)
    percentiles = np.linspace(0, 100, bins + 1)
    bin_edges = np.percentile(expected, percentiles)
    # 确保边界唯一
    bin_edges = np.unique(bin_edges)
    
    # 2. 分别统计两个分布在各箱的样本数
    exp_counts, _ = np.histogram(expected, bins=bin_edges)
    act_counts, _ = np.histogram(actual, bins=bin_edges)
    
    # 3. 计算占比(加入平滑因子避免零值)
    smooth = 0.5
    exp_prop = (exp_counts + smooth) / (np.sum(exp_counts) + smooth * len(exp_counts))
    act_prop = (act_counts + smooth) / (np.sum(act_counts) + smooth * len(act_counts))
    
    # 4. 计算PSI
    psi = np.sum((act_prop - exp_prop) * np.log(act_prop / exp_prop))
    
    return psi

# 使用示例
np.random.seed(42)
expected_data = np.random.normal(0, 1, 10000)
actual_data = np.random.normal(0.2, 1.1, 10000)  # 均值偏移0.2,标准差增大

psi_value = calculate_psi(expected_data, actual_data)
print(f"PSI = {psi_value:.4f}")  # 输出示例: PSI = 0.0452
PSI阈值参考:
  • PSI < 0.1:分布无显著变化,模型稳定
  • 0.1 ≤ PSI < 0.25:分布轻度偏移,需关注
  • PSI ≥ 0.25:分布显著偏移,需立即排查
上述阈值基于自然对数ln计算,若使用log10需相应调整。

3.6 分箱方法对比与选择指南

为帮助在实际项目中快速决策,下表总结了两种分箱方法的优劣与典型应用:

对比维度 等距分箱 等频分箱
对离群点的鲁棒性 弱,离群点可能导致大量空箱 强,离群点被自动归入首尾箱
对分布形状的敏感性 能反映分布密度变化 各箱样本量均衡,但可能掩盖局部密度变化
计算稳定性 低,空箱需额外处理 高,每个箱都有样本
推荐场景 变量值域有限且分布均匀 评分卡、信用风险模型、长尾分布
进阶技巧:在监控多个特征时,建议对每个特征单独进行等频分箱,而非使用全局统一分箱。因为不同特征的分布形态差异较大,统一分箱可能导致部分特征的分箱效果极差。