3. PSI 计算前置准备:数据分箱 (Binning) 的概念

在计算群体稳定性指标 (PSI) 之前,必须对连续型特征或离散值过多的特征进行分箱 (Binning) 处理。分箱的本质是将原始数据划分为若干个离散的区间(桶),然后用每个区间内的样本占比来刻画分布。PSI 正是通过比较这些区间占比的变化来衡量分布偏移的。

3.1 为什么需要分箱?

分箱是 PSI 计算的核心前置步骤,主要原因如下:

  • 消除噪声与过拟合:原始连续值可能包含大量细微波动,直接计算概率密度容易受噪声干扰。分箱后,每个区间的统计量更稳健。
  • 统一分布比较粒度:PSI 要求两个分布(如训练集 vs 线上集)在相同的区间划分下比较。分箱提供了标准化的“桶”结构。
  • 适应业务可解释性:分箱后的区间(如“年龄 20-30 岁”)比原始数值更符合业务人员的理解习惯。
核心原则:分箱方案必须在建模时确定,并在后续所有监控周期中保持一致。如果分箱边界发生改变,PSI 将失去可比性。

3.2 等距分箱 (Equal Width Binning)

等距分箱将特征的值域范围均匀划分为 k 个等宽的区间。每个区间的宽度 = (最大值 - 最小值) / k。

  • 优点:实现简单、计算快速;区间边界直观,便于业务解释。
  • 缺点:对数据分布敏感。如果数据集中在少数区间,其他区间可能样本极少甚至为空,导致 PSI 计算不稳定。
  • 适用场景:数据分布相对均匀,或特征值域范围已知且稳定的场景。

3.3 等频分箱 (Equal Frequency Binning)

等频分箱将数据按升序排列后,划分为 k 个区间,使得每个区间包含大致相同数量的样本(约总样本数 / k)。

  • 优点:每个区间都有足够的样本量,统计稳定性高;能自动适应数据的密度分布,在数据密集处划分更细。
  • 缺点:区间边界可能不是整数或业务含义不直观;当存在大量重复值时,难以严格保证等频。
  • 适用场景:长尾分布或偏态分布的特征,以及需要保证每个区间样本量充足的风控模型监控。

3.4 等距分箱 vs 等频分箱:核心对比

对比维度 等距分箱 等频分箱
划分依据 数值范围等宽 样本数量等量
区间宽度 固定 可变(数据密集处窄,稀疏处宽)
每个区间样本数 可能差异很大 大致相等
对异常值敏感度 高(异常值会拉宽区间) 低(异常值被归入首尾区间)
PSI 计算稳定性 若出现空桶,PSI 会异常 较高,空桶概率低
业务可解释性 强(边界为整数或固定值) 弱(边界为分位数,可能非整数)
实战建议:在风控特征巡检中,优先使用等频分箱(通常分 10 箱或 20 箱),以保证每个区间有足够的样本计算占比。如果业务方要求边界为整数,可在等频分箱后对边界做微调取整。

3.5 分箱流程与 PSI 的关系

下图展示了从原始特征到 PSI 计算的完整分箱流程,以及等距与等频两种策略在分布比较中的差异。

分箱策略对比与 PSI 计算流程 原始连续特征 等距分箱 (Equal Width) 等频分箱 (Equal Frequency) 区间 1: [0, 20) 样本占比 60% 区间 2: [20, 40) 样本占比 30% 区间 3: [40, 60] 样本占比 10% 区间 1: [0, 12) 样本占比 33% 区间 2: [12, 35) 样本占比 33% 区间 3: [35, 60] 样本占比 34% PSI 指标计算 分布偏移评估

3.6 代码示例:等距分箱与等频分箱实现

以下 Python 代码演示了使用 Pandas 和 NumPy 对同一组数据进行等距与等频分箱,并观察区间样本分布差异。

import pandas as pd
import numpy as np

# 生成示例数据:偏态分布(大部分集中在左侧)
np.random.seed(42)
data = np.concatenate([
    np.random.normal(20, 5, 800),   # 主体集中在 20 附近
    np.random.normal(50, 10, 200)   # 右侧长尾
])
data = np.clip(data, 0, 100).astype(int)
df = pd.DataFrame({'feature': data})

# 等距分箱:将 0-100 均匀分为 5 箱
df['equal_width_bin'] = pd.cut(df['feature'], bins=5, labels=['A','B','C','D','E'])
print("等距分箱各区间样本数:")
print(df['equal_width_bin'].value_counts().sort_index())

# 等频分箱:使用分位数分为 5 箱
df['equal_freq_bin'] = pd.qcut(df['feature'], q=5, labels=['a','b','c','d','e'])
print("\n等频分箱各区间样本数:")
print(df['equal_freq_bin'].value_counts().sort_index())
常见陷阱:使用 pd.qcut 时,如果数据中存在大量重复值,可能导致分箱失败(抛出 Bin edges must be unique 错误)。此时可先对数据添加微小随机噪声,或使用 duplicates='drop' 参数处理。

3.7 分箱数量选择指南

分箱数量 k 的选择直接影响 PSI 的敏感度和稳定性。下表总结了不同场景下的推荐值:

应用场景 推荐分箱数 说明
风控模型评分卡 10 ~ 20 兼顾细粒度与统计稳定性
营销响应模型 5 ~ 10 样本量较大时可适当减少
高频实时监控 5 ~ 10 减少计算开销,快速报警
小样本场景 (<1000) 3 ~ 5 避免区间样本过少导致 PSI 异常
经验法则:每个区间至少包含 50 个样本。如果某个区间样本数低于 50,应考虑合并相邻区间或减少总箱数。