3. PSI 计算基础:分箱方法的选择与实现
群体稳定性指标(PSI)的核心在于比较两个分布之间的差异。在计算 PSI 之前,必须先将连续变量或离散变量划分为若干个区间(即“分箱”)。分箱方法的选择直接决定了 PSI 的敏感度和可靠性。本章将系统讲解三种主流分箱方法:等距分箱、等频分箱与分位数分箱,并给出 Python 实现与选型建议。
3.1 分箱在 PSI 计算中的角色
PSI 的数学公式为:
PSI = Σ (实际占比_i - 预期占比_i) * ln(实际占比_i / 预期占比_i)
其中 i 代表第 i 个分箱。分箱决定了每个箱子的边界,进而决定了每个箱子的样本占比。如果分箱不合理,即使分布没有实质漂移,PSI 也可能异常波动;反之,如果分箱过于粗糙,则可能掩盖真实的漂移信号。
核心原则: 分箱应使每个箱子内的样本在统计上具有同质性,同时保证箱子间的区分度足够捕捉分布变化。
3.2 三种分箱方法对比
| 分箱方法 | 核心逻辑 | 优点 | 缺点 | 适用场景 |
|---|---|---|---|---|
| 等距分箱 | 将变量取值范围等分为 k 个宽度相同的区间 | 实现简单,边界直观,易于解释 | 对数据分布敏感,长尾分布下中间箱子样本稀疏 | 变量分布均匀、无极端异常值 |
| 等频分箱 | 使每个箱子包含大致相同的样本数量 | 箱子样本量均衡,避免空箱或稀疏箱 | 边界可能落在密集区域,导致相同值被分到不同箱子 | 样本量充足、分布偏态明显 |
| 分位数分箱 | 基于指定分位点(如 10%、20%…)划分边界 | 边界具有统计意义,对异常值鲁棒 | 分位点选择依赖经验,箱子数量固定 | 需要标准化分箱边界、跨时间对比 |
3.3 等距分箱实现
等距分箱将数据从最小值到最大值等分为 k 段。在 Python 中,可以使用 numpy.linspace 或 pandas.cut 实现。
import numpy as np
import pandas as pd
def equal_width_binning(data, bins=10):
"""
等距分箱
:param data: 一维数组或 Series
:param bins: 箱子数量
:return: 分箱标签、边界列表
"""
# 生成等距边界
bin_edges = np.linspace(data.min(), data.max(), bins + 1)
# 使用 cut 进行分箱
labels = pd.cut(data, bins=bin_edges, include_lowest=True, right=True)
return labels, bin_edges
# 示例
sample_data = np.random.randn(1000) * 50 + 200 # 模拟评分数据
labels, edges = equal_width_binning(sample_data, bins=10)
print("边界:", np.round(edges, 2))
注意: 等距分箱在数据存在极端异常值时,可能导致大部分样本集中在少数几个箱子中,其余箱子样本极少甚至为空,从而造成 PSI 计算不稳定。
3.4 等频分箱实现
等频分箱通过分位数保证每个箱子样本数大致相等。使用 pandas.qcut 可以快速实现。
def equal_freq_binning(data, bins=10):
"""
等频分箱
:param data: 一维数组或 Series
:param bins: 箱子数量
:return: 分箱标签、边界列表
"""
# qcut 按分位数切分,duplicates='drop' 处理重复边界
labels, bin_edges = pd.qcut(data, q=bins, retbins=True, duplicates='drop')
return labels, bin_edges
# 示例
labels, edges = equal_freq_binning(sample_data, bins=10)
print("各箱样本数:", labels.value_counts().sort_index().tolist())
实战技巧: 当数据中存在大量重复值时,
pd.qcut 可能因无法找到唯一分位点而报错。此时应设置 duplicates='drop',或先对数据添加微小噪声后再分箱。
3.5 分位数分箱实现
分位数分箱允许用户自定义分位点序列,适用于需要固定边界进行跨时间对比的场景。
def quantile_binning(data, quantiles=[0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9]):
"""
分位数分箱
:param data: 一维数组或 Series
:param quantiles: 分位点列表(0~1之间)
:return: 分箱标签、边界列表
"""
# 计算指定分位点的值
bin_edges = data.quantile(quantiles).unique()
bin_edges = np.sort(np.concatenate([[data.min()], bin_edges, [data.max()]]))
labels = pd.cut(data, bins=bin_edges, include_lowest=True, right=True)
return labels, bin_edges
# 示例:使用十分位点
quantiles = [i/10 for i in range(1, 10)]
labels, edges = quantile_binning(pd.Series(sample_data), quantiles)
print("分位边界:", np.round(edges, 2))
3.6 分箱方法选择决策流程
下图展示了在实际项目中如何根据数据特征选择合适的分箱方法:
3.7 分箱数量与 PSI 敏感度
分箱数量(k)是另一个关键参数。经验法则如下:
- k = 10:行业默认值,适用于大多数评分卡和风控模型监控。
- k = 5~8:样本量较小(< 1000)或变量取值有限时使用,避免箱子过细导致统计噪声。
- k = 15~20:样本量极大(> 100000)且需要捕捉细微漂移时使用,但需警惕过拟合。
推荐做法: 在开发阶段,使用 k=10 的分位数分箱作为基线;上线后根据实际 PSI 波动情况,通过敏感性分析调整分箱数量。
3.8 分箱边界对齐:跨时间 PSI 计算的关键
在计算 PSI 时,必须使用同一套分箱边界对预期分布和实际分布进行划分。如果每次重新计算边界,PSI 将失去可比性。
def psi_with_fixed_bins(expected, actual, bin_edges):
"""
使用固定边界计算 PSI
:param expected: 预期分布数据
:param actual: 实际分布数据
:param bin_edges: 固定的分箱边界
:return: PSI 值
"""
# 使用相同的边界对两个分布分箱
exp_binned = pd.cut(expected, bins=bin_edges, include_lowest=True, right=True)
act_binned = pd.cut(actual, bins=bin_edges, include_lowest=True, right=True)
# 计算各箱占比
exp_counts = exp_binned.value_counts().sort_index()
act_counts = act_binned.value_counts().sort_index()
exp_pct = exp_counts / len(expected)
act_pct = act_counts / len(actual)
# 处理空箱:加极小值避免除零
exp_pct = exp_pct.replace(0, 1e-6)
act_pct = act_pct.replace(0, 1e-6)
# 计算 PSI
psi = np.sum((act_pct - exp_pct) * np.log(act_pct / exp_pct))
return psi
# 示例:使用训练集确定边界,在测试集上计算 PSI
train_data = np.random.randn(5000) * 50 + 200
test_data = np.random.randn(5000) * 60 + 210 # 模拟漂移
_, fixed_edges = equal_freq_binning(train_data, bins=10)
psi_value = psi_with_fixed_bins(train_data, test_data, fixed_edges)
print(f"PSI = {psi_value:.4f}")
常见错误: 在计算实际分布时重新分箱,导致边界不一致。这会使 PSI 值虚高或虚低,无法反映真实漂移。务必在模型开发阶段就锁定分箱边界。
3.9 分箱方法选型总结
| 场景 | 推荐分箱方法 | 推荐箱子数 | 注意事项 |
|---|---|---|---|
| 信用评分卡(分数范围固定) | 等距分箱 | 10~20 | 边界需与业务规则对齐 |
| 风控模型特征监控 | 等频分箱 | 10 | 处理重复值,避免 qcut 报错 |
| 跨时间分布对比 | 分位数分箱 | 10 | 锁定分位点,确保边界一致 |
| 小样本(< 500) | 等频分箱 | 5~8 | 合并稀疏箱,保证每箱至少 50 样本 |
| 高精度漂移检测 | 分位数分箱 | 15~20 | 结合业务含义调整分位点 |
选择合适的分箱方法是 PSI 计算的基础。在实际项目中,建议先使用等频分箱快速验证,再根据数据分布特征切换到分位数分箱或等距分箱,并始终锁定边界用于后续监控。