2. PSI 数学原理与计算公式
群体稳定性指标(Population Stability Index, PSI)是风控模型监控中最核心的量化指标,用于衡量模型评分在 实际分布 与 预期分布 之间的偏移程度。本章从数学推导、分箱策略、对比逻辑到数值解读,完整拆解 PSI 的计算全链路。
2.1 PSI 的数学推导
PSI 的数学基础源于信息论中的 KL 散度(Kullback-Leibler divergence),但做了对称化处理。其核心思想是:将连续型模型评分划分为 k 个离散区间(分箱),然后逐箱计算实际占比与预期占比的差异,并加权求和。
标准计算公式:
PSI = Σ (实际占比_i - 预期占比_i) × ln(实际占比_i / 预期占比_i)
其中:
- 实际占比_i:当前监控周期内,落在第 i 个分箱中的样本数占总样本数的比例。
- 预期占比_i:模型开发或基准周期内,落在第 i 个分箱中的样本数占总样本数的比例。
- ln:自然对数,用于放大占比差异的非线性影响。
- Σ:对所有分箱求和,得到最终的 PSI 值。
数学推导要点:
- 从 KL 散度出发:KL(P||Q) = Σ P_i × ln(P_i / Q_i),其中 P 为实际分布,Q 为预期分布。KL 散度是非对称的,即 KL(P||Q) ≠ KL(Q||P)。
- 对称化处理:PSI 采用 (P_i - Q_i) × ln(P_i / Q_i) 的形式,既保留了方向性,又通过差值项实现了对称性,使得 PSI 对双向偏移都敏感。
- 当 P_i = Q_i 时:ln(P_i / Q_i) = 0,且 (P_i - Q_i) = 0,该分箱贡献为 0,PSI = 0,表示无偏移。
- 当 P_i 或 Q_i 为 0 时:为避免 ln(0) 或除以 0,通常对占比做微小平滑处理(如加 0.0001),或合并空箱。
💡 关键理解: PSI 本质上衡量的是两个概率分布之间的“距离”。值越大,说明实际评分分布与预期评分分布差异越大,模型可能发生了漂移。
2.2 分箱策略:等频 vs 等距
分箱是 PSI 计算的前置步骤,直接影响 PSI 的敏感度和稳定性。主流策略有两种:等频分箱 和 等距分箱。
| 对比维度 | 等频分箱(Equal Frequency) | 等距分箱(Equal Width) |
|---|---|---|
| 定义 | 每个分箱包含大致相同数量的样本 | 每个分箱的评分区间宽度相同 |
| 分箱依据 | 基于样本百分位数(如 10%、20%…) | 基于评分值域等分(如 0-100 分,每 10 分一箱) |
| 优点 | 避免空箱或样本极少的箱;对长尾分布鲁棒 | 分箱边界固定,跨周期可比性强;解释直观 |
| 缺点 | 分箱边界随样本分布变化,跨周期边界不一致 | 可能出现空箱或样本极少的箱,导致计算不稳定 |
| 风控场景推荐 | 监控周期内样本量波动大时优先使用 | 评分尺度固定(如 300-900 分)且样本充足时使用 |
分箱数量建议: 通常取 10 箱(即 10 个分位点),样本量较大时可取 20 箱,样本量较小(如 < 5000)时建议取 5 箱,避免统计噪声。
⚠️ 常见陷阱: 不要对预期分布和实际分布使用不同的分箱策略。必须基于 预期分布 的分箱边界,将实际样本映射到相同的分箱中,否则 PSI 会失真。
2.3 实际分布与预期分布的对比逻辑
PSI 的计算过程本质上是一个 逐箱对比 的过程。以下 SVG 图展示了从原始评分到 PSI 值的完整对比逻辑。
2.4 PSI 值含义解读
PSI 是一个无量纲的数值,其大小直接反映模型分布的偏移程度。行业通用的判断阈值如下:
| PSI 范围 | 漂移程度 | 建议动作 |
|---|---|---|
| PSI < 0.1 | 无显著漂移 | 模型稳定,无需干预 |
| 0.1 ≤ PSI < 0.25 | 轻度漂移 | 需关注,排查特征分布变化,准备模型重训 |
| PSI ≥ 0.25 | 严重漂移 | 立即告警,暂停模型使用,启动重训或回退 |
解读注意事项:
- 阈值不是绝对的:0.1 和 0.25 是行业经验值,实际业务中可根据模型重要性、样本量、业务容忍度做微调。例如,信贷审批模型可适当放宽至 0.15/0.3,反欺诈模型建议收紧至 0.08/0.2。
- 分箱数影响 PSI 绝对值:分箱越多,PSI 通常越大。使用 10 箱时 0.1 的阈值,若改用 20 箱,阈值应相应上调至约 0.15。
- PSI 不能定位漂移原因:PSI 只告诉你“漂移了”,但不告诉你“为什么漂移”。需要结合特征 PSI、变量分布图、业务事件日志做根因分析。
- 样本量不足时 PSI 不可靠:当监控样本量 < 1000 时,PSI 的统计波动较大,建议结合 KS 检验或卡方检验辅助判断。
📌 实战要点: 在风控模型监控系统中,PSI 通常按 日/周/月 粒度计算,并与预设阈值(如 0.1 和 0.25)比较,触发不同级别的告警。阈值调优是下一章的核心内容。
2.5 PSI 计算代码示例(Python)
以下代码展示了基于等频分箱的 PSI 计算实现,可直接用于模型监控脚本中。
import numpy as np
import pandas as pd
def calculate_psi(expected, actual, bins=10):
"""
计算群体稳定性指标 (PSI)
参数:
expected: array-like, 预期分布(基准样本评分)
actual: array-like, 实际分布(监控样本评分)
bins: int, 分箱数量(默认10箱等频分箱)
返回:
psi: float, PSI 值
psi_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, right=True)
actual_bins = np.digitize(actual, bin_edges, right=True)
# 计算各箱占比
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)
# 平滑处理,避免 ln(0)
epsilon = 1e-6
expected_pct = np.clip(expected_pct, epsilon, 1 - epsilon)
actual_pct = np.clip(actual_pct, epsilon, 1 - epsilon)
# 逐箱计算 PSI 贡献
psi_components = (actual_pct - expected_pct) * np.log(actual_pct / expected_pct)
psi = np.sum(psi_components)
# 构建明细 DataFrame
psi_df = pd.DataFrame({
'分箱': range(1, bins + 1),
'预期占比': expected_pct,
'实际占比': actual_pct,
'PSI贡献': psi_components
})
return psi, psi_df
# 示例用法
np.random.seed(42)
expected_scores = np.random.normal(600, 100, 10000) # 基准分布
actual_scores = np.random.normal(620, 110, 10000) # 偏移后的分布
psi_value, psi_detail = calculate_psi(expected_scores, actual_scores, bins=10)
print(f"PSI 值: {psi_value:.4f}")
print(psi_detail.head())
代码输出示例:
PSI 值: 0.0327
分箱 预期占比 实际占比 PSI贡献
0 1 0.1000 0.0860 0.0021
1 2 0.1000 0.0910 0.0009
2 3 0.1000 0.0950 0.0003
3 4 0.1000 0.0980 0.0000
4 5 0.1000 0.1020 0.0000
💡 代码解读: 上述示例中 PSI = 0.0327 < 0.1,表示模型分布无显著漂移。实际应用中,可将此函数封装到监控流水线中,每日/每周自动计算并触发告警。