2. 分箱类型:等距分箱、等频分箱、自定义分箱、最优分箱

分箱(Binning)是将连续变量离散化为有限个区间(箱)的过程,是评分卡建模中特征工程的核心步骤。不同的分箱策略直接影响变量的预测能力、业务可解释性以及后续的拒绝原因分析。本节系统梳理四种主流分箱类型:等距分箱、等频分箱、自定义分箱和最优分箱(含决策树分箱与卡方分箱)。

2.1 分箱类型总览

下表从分箱原理、适用场景、优缺点三个维度对比四种分箱方法,帮助建模人员快速选型。

分箱类型 核心原理 适用场景 主要优点 主要缺点
等距分箱 将变量取值范围划分为宽度相等的区间 数据分布均匀、无极端异常值 实现简单、箱宽一致 易受异常值影响、箱内样本可能极不均匀
等频分箱 将变量取值范围划分为包含相同样本数的区间 数据分布偏态、需要保证每箱样本量 每箱样本量均衡、稳定性好 可能将相近值分到不同箱、边界不自然
自定义分箱 根据业务知识或监管要求手动设定切分点 业务规则明确、监管合规要求 业务可解释性强、灵活可控 依赖专家经验、可能过拟合
最优分箱 基于统计检验或信息增益自动寻找最优切分点 追求预测性能、自动化建模流程 数据驱动、信息损失最小 计算成本高、可能过拟合
选型建议:在风控评分卡建模中,推荐优先尝试最优分箱(卡方分箱或决策树分箱),若业务有强约束(如监管要求年龄按“18-25, 26-35, 36-45, 46-55, 55+”分段),则使用自定义分箱作为兜底方案。

2.2 等距分箱(Equal-Width Binning)

等距分箱将变量的取值范围 [min, max] 划分为 k 个宽度相等的区间,每个区间的宽度为 (max - min) / k。该方法对数据分布无假设,实现成本最低。

计算步骤:

  1. 确定分箱数量 k(通常取 5~10)。
  2. 计算箱宽 w = (max - min) / k。
  3. 生成切分点:min + w, min + 2w, ..., min + (k-1)w。
  4. 将每个观测值分配到对应的箱中。
# Python 示例:等距分箱
import pandas as pd
import numpy as np

def equal_width_binning(data, k=5):
    min_val, max_val = data.min(), data.max()
    bins = np.linspace(min_val, max_val, k+1)
    return pd.cut(data, bins=bins, include_lowest=True)

# 示例:对年龄变量进行等距分箱
ages = [22, 25, 28, 32, 35, 38, 42, 45, 48, 52]
bins = equal_width_binning(pd.Series(ages), k=4)
print(bins)
风险提示:等距分箱对异常值极其敏感。若变量存在极端值(如收入变量中个别“亿万富翁”),会导致大部分样本挤入少数几个箱,其余箱近乎为空,严重破坏分箱均衡性。

2.3 等频分箱(Equal-Frequency Binning)

等频分箱将变量取值范围划分为 k 个区间,使得每个区间包含大致相同的样本数(约 n/k 个)。该方法能有效应对偏态分布,保证每箱都有足够的样本进行统计推断。

计算步骤:

  1. 确定分箱数量 k。
  2. 将数据按升序排序。
  3. 在分位数位置 100/k, 200/k, ..., (k-1)*100/k 处设置切分点。
  4. 将每个观测值分配到对应的箱中。
# Python 示例:等频分箱
def equal_frequency_binning(data, k=5):
    # 使用分位数作为切分点
    quantiles = np.linspace(0, 1, k+1)
    bins = data.quantile(quantiles).values
    # 确保切分点唯一
    bins = np.unique(bins)
    return pd.cut(data, bins=bins, include_lowest=True, duplicates='drop')

# 示例:对收入变量进行等频分箱
incomes = [3000, 4500, 5200, 5800, 6200, 7500, 8800, 12000, 15000, 25000]
bins = equal_frequency_binning(pd.Series(incomes), k=4)
print(bins)
关键对比:等距分箱保证“箱宽一致”,等频分箱保证“箱量一致”。在风控建模中,等频分箱通常优于等距分箱,因为它能避免出现空箱或样本过少的箱,从而保证后续WOE(Weight of Evidence)和IV(Information Value)计算的稳定性。

2.4 自定义分箱(Custom Binning)

自定义分箱完全由建模人员根据业务逻辑、监管要求或历史经验手动设定切分点。该方法在金融风控领域应用广泛,尤其是涉及合规审查的场景。

典型应用场景:

  • 监管合规:如银保监会要求“年龄”按特定区间分段。
  • 业务常识:如“授信额度”按产品层级(0-1万、1-5万、5-20万、20万+)分段。
  • 拒绝原因分析:为每个箱赋予明确的业务含义,便于生成拒绝原因码。
# Python 示例:自定义分箱
def custom_binning(data, cut_points, labels=None):
    # cut_points: 切分点列表,如 [0, 30, 50, 100]
    # labels: 箱标签,如 ['低', '中', '高']
    bins = [-np.inf] + cut_points + [np.inf]
    return pd.cut(data, bins=bins, labels=labels, include_lowest=True)

# 示例:对年龄按业务规则分箱
ages = [18, 22, 28, 35, 42, 50, 58, 65]
cut_points = [25, 35, 45, 55]
labels = ['18-25', '26-35', '36-45', '46-55', '55+']
bins = custom_binning(pd.Series(ages), cut_points, labels)
print(bins)
最佳实践:自定义分箱的切分点应尽量与业务决策点对齐。例如,在信用卡额度管理中,可将“月收入”按“0-3000(无稳定收入)、3000-8000(工薪层)、8000-20000(中产)、20000+(高净值)”分段,每个箱对应不同的授信策略和拒绝原因。

2.5 最优分箱(Optimal Binning)

最优分箱通过统计检验或机器学习算法自动寻找使目标变量区分度最大的切分点。本节重点介绍两种最常用的最优分箱方法:决策树分箱和卡方分箱。

2.5.1 决策树分箱(Decision Tree Binning)

决策树分箱利用单变量决策树(CART算法)对连续变量进行分割。算法以目标变量(如好坏标签)作为监督信号,选择使基尼系数或信息增益最大化的切分点。

算法流程:

  1. 将连续变量作为唯一特征,目标变量作为标签。
  2. 训练一个深度受限的决策树(通常设置最大深度为3~5,或最小叶子节点样本数为总样本的5%)。
  3. 提取决策树的所有切分点作为分箱边界。
  4. 将原始变量映射到决策树叶子节点对应的箱中。
# Python 示例:决策树分箱
from sklearn.tree import DecisionTreeClassifier
import numpy as np

def decision_tree_binning(X, y, max_depth=3, min_samples_leaf=0.05):
    # X: 连续变量(需reshape为二维)
    # y: 二分类目标变量
    clf = DecisionTreeClassifier(
        max_depth=max_depth,
        min_samples_leaf=min_samples_leaf,
        criterion='gini'
    )
    clf.fit(X.reshape(-1, 1), y)
    
    # 提取切分点
    tree = clf.tree_
    threshold = tree.threshold[tree.feature == 0]  # 特征索引为0
    threshold = threshold[threshold != -2]  # 移除叶子节点
    cut_points = np.sort(threshold)
    
    # 生成分箱
    bins = [-np.inf] + list(cut_points) + [np.inf]
    return pd.cut(X, bins=bins, include_lowest=True), cut_points

# 示例
X = np.array([22, 25, 28, 32, 35, 38, 42, 45, 48, 52])
y = np.array([0, 0, 0, 1, 1, 1, 1, 0, 0, 1])  # 好坏标签
bins, cut_points = decision_tree_binning(X, y, max_depth=2)
print("切分点:", cut_points)
print("分箱结果:", bins)

2.5.2 卡方分箱(Chi-Merge Binning)

卡方分箱是一种自底向上的合并式分箱方法。它从每个观测值作为一个独立箱开始,迭代合并卡方统计量最小的相邻箱对,直到满足停止条件(如达到预设箱数或所有相邻箱的卡方值均大于阈值)。

算法流程:

  1. 初始化:将每个观测值视为一个独立箱。
  2. 计算卡方值:对每对相邻箱,计算卡方统计量:
    χ² = Σᵢ Σⱼ (Oᵢⱼ - Eᵢⱼ)² / Eᵢⱼ
    其中 Oᵢⱼ 为观测频数,Eᵢⱼ 为期望频数。
  3. 合并:合并卡方值最小的一对相邻箱。
  4. 迭代:重复步骤2~3,直到箱数达到预设值或所有卡方值均大于显著性水平对应的临界值。
# Python 示例:卡方分箱(简化版)
import scipy.stats as stats

def chi_merge_binning(X, y, max_bins=5):
    # 初始化:每个观测值作为一个箱
    data = pd.DataFrame({'X': X, 'y': y})
    data = data.sort_values('X').reset_index(drop=True)
    bins = list(range(len(data)))  # 箱编号
    
    while len(set(bins)) > max_bins:
        # 计算相邻箱的卡方值
        chi_values = []
        unique_bins = sorted(set(bins))
        for i in range(len(unique_bins)-1):
            b1 = unique_bins[i]
            b2 = unique_bins[i+1]
            # 构建2x2列联表
            group1 = data[bins == b1]['y']
            group2 = data[bins == b2]['y']
            table = np.array([
                [sum(group1==0), sum(group1==1)],
                [sum(group2==0), sum(group2==1)]
            ])
            # 计算卡方统计量
            chi2, _, _, _ = stats.chi2_contingency(table, correction=False)
            chi_values.append(chi2)
        
        # 合并卡方值最小的相邻箱
        min_idx = np.argmin(chi_values)
        b1 = unique_bins[min_idx]
        b2 = unique_bins[min_idx+1]
        bins = [b1 if b == b2 else b for b in bins]
    
    # 生成分箱边界
    unique_bins = sorted(set(bins))
    cut_points = []
    for i in range(len(unique_bins)-1):
        b1 = unique_bins[i]
        b2 = unique_bins[i+1]
        # 取两个箱之间的中点作为切分点
        max_val_b1 = data[bins == b1]['X'].max()
        min_val_b2 = data[bins == b2]['X'].min()
        cut_points.append((max_val_b1 + min_val_b2) / 2)
    
    bins_final = [-np.inf] + cut_points + [np.inf]
    return pd.cut(X, bins=bins_final, include_lowest=True), cut_points

# 示例
X = np.array([22, 25, 28, 32, 35, 38, 42, 45, 48, 52])
y = np.array([0, 0, 0, 1, 1, 1, 1, 0, 0, 1])
bins, cut_points = chi_merge_binning(X, y, max_bins=4)
print("切分点:", cut_points)
print("分箱结果:", bins)
方法对比:决策树分箱是“自上而下”的分割式方法,卡方分箱是“自下而上”的合并式方法。决策树分箱计算效率更高,适合大数据量;卡方分箱能更好地保持相邻箱的统计相似性,适合需要严格统计检验的场景。

2.6 最优分箱流程对比图

下图直观对比了决策树分箱(自上而下分割)与卡方分箱(自下而上合并)的核心流程差异。

最优分箱流程对比:决策树分箱 vs 卡方分箱 决策树分箱(自上而下) 连续变量 + 目标标签 选择基尼系数最小切分点 递归分割左右子节点 达到最大深度或最小叶子样本 卡方分箱(自下而上) 每个观测值作为一个箱 计算所有相邻箱的卡方值 合并卡方值最小的相邻箱 达到预设箱数或卡方阈值 决策树分箱:分割式,效率高,适合大数据;卡方分箱:合并式,统计检验严谨,适合小数据

2.7 分箱效果评估指标

无论采用哪种分箱方法,都需要通过以下指标评估分箱质量:

指标 计算公式 评估标准
IV(信息量) Σ (好占比 - 坏占比) × ln(好占比/坏占比) IV > 0.3 为强预测力;0.1~0.3 为中等;< 0.1 为弱
WOE(证据权重) ln(好占比 / 坏占比) WOE应单调递增或递减,且各箱WOE差异明显
卡方检验 p 值 基于列联表的卡方检验 p < 0.05 表示相邻箱有显著差异,不宜合并
每箱样本占比 箱内样本数 / 总样本数 每箱占比应 > 5%,避免过拟合
常见陷阱:最优分箱虽然能最大化预测性能,但可能导致分箱边界过于复杂,难以在拒绝原因分析中生成清晰的拒绝码。建议在最优分箱后,对边界进行“业务对齐”微调,确保每个箱都有明确的业务含义。

2.8 分箱类型选择决策树

下图帮助建模人员根据数据特征和业务需求快速选择合适的分箱方法。

分箱类型选择决策树 连续变量分箱需求 是否有业务/监管约束? 是 自定义分箱 否 数据分布是否均匀? 是 等距分箱 否 等频分箱 若追求预测性能且无业务约束,优先使用最优分箱(决策树分箱或卡方分箱)

2.9 分箱在拒绝原因分析中的应用

分箱不仅是特征工程步骤,更是拒绝原因分析的基础。每个箱对应一个明确的业务含义,当客户被拒绝时,系统可根据其所在箱直接映射出拒绝原因码。

示例:年龄变量分箱与拒绝原因映射

分箱区间 箱标签 WOE 拒绝原因码 拒绝原因描述
[18, 25) 青年低龄 -0.45 AGE_01 年龄过低,收入稳定性不足
[25, 35) 青年中龄 0.12 — 正常区间,不触发拒绝
[35, 50) 中年 0.28 — 正常区间,不触发拒绝
[50, 65) 中老年 -0.08 AGE_02 年龄偏高,还款能力下降风险
[65, +∞) 老年 -0.62 AGE_03 年龄过高,不符合授信政策
实践要点:在拒绝原因分析中,每个箱的拒绝原因码应保持稳定,避免因分箱边界微调导致拒绝原因频繁变更。建议在模型上线前,将分箱边界和对应的拒绝原因码固化到决策引擎配置中。