3. PSI指标详解:群体稳定性指标的数学原理、计算公式、分箱策略与业务解读
群体稳定性指标(Population Stability Index, PSI)是风控模型监控中最核心的量化指标之一。它衡量的是模型评分或关键特征在两个时间窗口(通常为建模样本 vs. 当前样本,或上一监控周期 vs. 当前周期)之间的分布偏移程度。PSI 值越大,说明群体分布变化越剧烈,模型失效或业务环境发生结构性改变的风险越高。
3.1 数学原理与计算公式
PSI 的数学基础是信息论中的 Kullback-Leibler 散度(相对熵)的对称化变体。它通过比较两个分布在各分箱上的占比差异,量化整体偏移幅度。
标准计算公式:
PSI = Σ (Actual_i - Expected_i) × ln(Actual_i / Expected_i)
其中:
- Expected_i = 基准分布(如建模样本)在第 i 个分箱中的占比
- Actual_i = 当前分布(如实时交易样本)在第 i 个分箱中的占比
- i = 1, 2, ..., N(N 为分箱总数)
计算步骤分解:
- 分箱:将模型评分或特征值域划分为 N 个区间(通常 10~20 箱)。
- 统计占比:分别计算基准分布和当前分布落在每个箱内的样本比例。
- 计算单箱贡献:对每个箱,计算 (Actual% - Expected%) × ln(Actual% / Expected%)。
- 求和:将所有箱的贡献值相加,得到最终 PSI 值。
⚠ 零值处理:当某个分箱中 Actual% 或 Expected% 为 0 时,ln(0) 无定义。实际工程中通常采用两种方式:① 将 0 替换为一个极小正数(如 0.0001);② 合并空箱到相邻箱,确保每个箱都有非零占比。
3.2 分箱策略详解
分箱方式直接影响 PSI 计算的稳定性和敏感性。不同的分箱策略适用于不同的业务场景和数据类型。
| 分箱策略 | 方法描述 | 适用场景 | 优点 | 缺点 |
|---|---|---|---|---|
| 等距分箱 | 将值域按固定宽度均匀切分 | 评分卡分数(如 300~850 分) | 实现简单,箱边界固定,便于跨周期对比 | 数据分布不均时可能出现空箱或样本稀疏箱 |
| 等频分箱 | 按样本量均分,每箱包含相同数量的样本 | 特征分布偏态严重时 | 避免空箱,每箱统计量稳定 | 箱边界随样本分布变化,跨周期对比时边界不一致 |
| 最优分箱 | 基于决策树或卡方检验自动寻找最佳切分点 | 特征与目标变量关系复杂时 | 信息损失最小,分箱结果可解释性强 | 计算开销大,依赖目标变量,不适合纯分布监控 |
| 业务规则分箱 | 根据业务经验或监管要求定义箱边界 | 监管报送、风险等级划分 | 业务含义清晰,便于合规解释 | 可能忽略数据内在分布特征 |
推荐实践:在实时交易风控巡检中,建议对模型评分采用等距分箱(如每 50 分一箱),对连续型特征采用等频分箱(如 10 箱),对离散型特征按业务规则分箱。分箱数量一般控制在 10~20 箱,过少会掩盖局部偏移,过多则引入噪声。
3.3 PSI 阈值与业务解读
PSI 的数值大小直接对应群体稳定性的不同等级。以下是业界通用的解读标准:
| PSI 范围 | 稳定性等级 | 业务含义 | 建议动作 |
|---|---|---|---|
| PSI < 0.1 | 稳定 | 群体分布无显著变化,模型表现可预期 | 正常监控,无需干预 |
| 0.1 ≤ PSI < 0.25 | 轻度偏移 | 群体分布出现一定变化,需关注趋势 | 增加监控频率,排查业务或数据源变化 |
| PSI ≥ 0.25 | 严重偏移 | 群体分布发生结构性改变,模型可能失效 | 立即触发告警,启动模型重训或业务规则调整 |
阈值不是绝对的:上述阈值是经验值,实际应用中应根据业务风险容忍度调整。例如,在反欺诈场景中,PSI > 0.15 就可能需要立即响应;而在用户画像分析场景中,PSI < 0.3 可能仍可接受。建议结合历史数据为每个监控指标建立个性化的基线阈值。
3.4 PSI 计算流程与架构
下图展示了实时交易风控巡检中 PSI 计算的完整数据流与架构设计:
3.5 PSI 与 KS、Gini 的对比
在风控模型监控体系中,PSI 常与区分度指标(KS、Gini)配合使用。下表清晰展示了三者的核心差异:
| 维度 | PSI(群体稳定性) | KS(区分度) | Gini(排序能力) |
|---|---|---|---|
| 监控对象 | 模型评分或特征的分布偏移 | 好坏样本的累计分布差异 | 模型对好坏样本的排序能力 |
| 计算基础 | 两个时间窗口的分布对比 | 同一时间窗口的好坏样本对比 | ROC 曲线下面积 |
| 业务含义 | 群体是否发生结构性变化 | 模型能否有效区分好坏客户 | 模型排序的准确度 |
| 触发告警 | PSI > 0.25 | KS 下降 > 20% | Gini 下降 > 15% |
| 监控频率 | 每日 / 每小时 | 每周 / 每日 | 每周 / 每月 |
最佳实践:在实时交易风控巡检中,建议将 PSI 作为前置预警指标,KS 和 Gini 作为后验验证指标。当 PSI 触发轻度偏移时,立即排查业务原因;若 PSI 持续恶化,再结合 KS/Gini 判断模型是否需要重训。
3.6 PSI 在 SQL 中的实现示例
以下 SQL 代码展示了如何在 Hive/Spark SQL 中实现 PSI 计算,适用于离线批量巡检场景:
-- 步骤1:对基准分布和当前分布分别进行等频分箱并统计占比
WITH base_dist AS (
SELECT
CASE
WHEN score < 300 THEN '0-300'
WHEN score < 350 THEN '300-350'
WHEN score < 400 THEN '350-400'
WHEN score < 450 THEN '400-450'
WHEN score < 500 THEN '450-500'
WHEN score < 550 THEN '500-550'
WHEN score < 600 THEN '550-600'
WHEN score < 650 THEN '600-650'
WHEN score < 700 THEN '650-700'
ELSE '700+'
END AS score_bin,
COUNT(*) AS base_cnt
FROM model_scores_base
GROUP BY 1
),
current_dist AS (
SELECT
CASE
WHEN score < 300 THEN '0-300'
WHEN score < 350 THEN '300-350'
WHEN score < 400 THEN '350-400'
WHEN score < 450 THEN '400-450'
WHEN score < 500 THEN '450-500'
WHEN score < 550 THEN '500-550'
WHEN score < 600 THEN '550-600'
WHEN score < 650 THEN '600-650'
WHEN score < 700 THEN '650-700'
ELSE '700+'
END AS score_bin,
COUNT(*) AS current_cnt
FROM model_scores_current
WHERE dt = '2025-03-01'
GROUP BY 1
),
-- 步骤2:计算各箱占比和 PSI 贡献
psi_calc AS (
SELECT
b.score_bin,
b.base_cnt,
c.current_cnt,
b.base_cnt / SUM(b.base_cnt) OVER() AS base_pct,
c.current_cnt / SUM(c.current_cnt) OVER() AS current_pct
FROM base_dist b
FULL OUTER JOIN current_dist c ON b.score_bin = c.score_bin
)
-- 步骤3:汇总 PSI 值
SELECT
ROUND(SUM(
(current_pct - base_pct) * LN(current_pct / base_pct)
), 6) AS psi_value
FROM psi_calc
WHERE base_pct > 0 AND current_pct > 0; -- 过滤空箱
Spark 优化提示:在 PySpark 中,可以使用
approxQuantile() 函数动态计算等频分箱边界,避免硬编码。对于实时流计算(Structured Streaming),建议将 PSI 计算封装为 foreachBatch 中的微批处理,每 5 分钟输出一次当前 PSI 值到监控看板。