金融风控中的特征分箱进阶:决策树与卡方分箱实战解析

在金融风控建模过程中,特征工程的质量往往直接决定了模型效果的上限。许多数据分析师虽然掌握了基础的等频、等距分箱方法,但在面对真实业务场景时,这些无监督分箱技术常常显得力不从心。本文将带你深入两种有监督分箱方法——决策树分箱和卡方分箱的实战应用,并构建完整的评估流水线。

1. 为什么需要进阶分箱技术?

传统分箱方法如pandas.cut虽然简单易用,但在金融风控场景中存在明显局限。等距分箱对异常值敏感,等频分箱可能破坏特征与目标变量的相关性。而有监督分箱能够充分利用标签信息,使分箱结果更有利于模型学习。

关键优势对比:

分箱类型是否利用标签抗异常值能力保持单调性计算复杂度
等距分箱否弱无保证低
等频分箱否中无保证中
决策树分箱是强有保证高
卡方分箱是中无保证中

提示:在金融评分卡开发中,通常要求特征具有单调的WOE趋势,这时决策树分箱的优势尤为明显。

2. 决策树分箱实战

决策树分箱的核心思想是利用树模型的划分点作为分箱边界。这种方法天然具备特征选择能力,且能自动处理非线性关系。

2.1 基于sklearn的实现

from sklearn.tree import DecisionTreeClassifier
import numpy as np

def tree_binning(feature, target, max_leaf_nodes=5):
    # 确保输入为二维数组
    X = np.array(feature).reshape(-1, 1)
    y = np.array(target)
    
    # 训练决策树
    tree = DecisionTreeClassifier(
        max_leaf_nodes=max_leaf_nodes,
        random_state=42
    )
    tree.fit(X, y)
    
    # 提取分箱边界
    thresholds = tree.tree_.threshold[tree.tree_.threshold != -2]
    bins = np.sort(thresholds)
    
    # 添加最小最大值
    return np.concatenate([[-np.inf], bins, [np.inf]])

参数调优要点:

  • max_leaf_nodes:控制分箱数量,通常3-5个箱足够
  • min_samples_leaf:防止过拟合,建议设置为总样本的5%
  • class_weight:不平衡数据时设为"balanced"

2.2 分箱效果评估

决策树分箱后,我们需要检查WOE(Weight of Evidence)的单调性:

import pandas as pd

def calculate_woe(df, feature, target):
    df_grouped = df.groupby(feature)[target].agg(['count', 'sum'])
    df_grouped.columns = ['total', 'bad']
    df_grouped['good'] = df_grouped['total'] - df_grouped['bad']
    
    # 计算WOE和IV
    bad_rate_total = df_grouped['bad'].sum() / df_grouped['total'].sum()
    good_rate_total = 1 - bad_rate_total
    
    df_grouped['bad_rate'] = df_grouped['bad'] / df_grouped['total']
    df_grouped['good_rate'] = df_grouped['good'] / df_grouped['total']
    
    df_grouped['woe'] = np.log(
        (df_grouped['good'] / df_grouped['good'].sum()) / 
        (df_grouped['bad'] / df_grouped['bad'].sum())
    )
    
    df_grouped['iv'] = (
        (df_grouped['good'] / df_grouped['good'].sum()) - 
        (df_grouped['bad'] / df_grouped['bad'].sum())
    ) * df_grouped['woe']
    
    return df_grouped

3. 卡方分箱技术详解

卡方分箱基于相邻区间的卡方统计量进行合并,适用于分类变量和连续变量。与决策树分箱相比,它不强制要求单调性,但能更好地保留原始分布特征。

3.1 卡方分箱实现步骤

  1. 初始化:将连续变量排序后,每个值作为一个单独区间
  2. 计算卡方值:对每对相邻区间计算卡方统计量
  3. 合并区间:合并卡方值最小的相邻区间
  4. 停止条件:直到满足预设的箱数或卡方阈值

Python实现核心代码:

from scipy.stats import chi2_contingency

def chi2_merge(data, target, max_bins=5):
    # 初始化为每个唯一值一个箱
    unique_values = np.sort(data.unique())
    bins = [[val] for val in unique_values]
    
    while len(bins) > max_bins:
        min_chi2 = float('inf')
        best_idx = -1
        
        # 寻找最佳合并对
        for i in range(len(bins)-1):
            # 构建列联表
            contigency = pd.crosstab(
                data.isin(bins[i]+bins[i+1]),
                target
            )
            
            # 计算卡方值
            chi2 = chi2_contingency(contigency)[0]
            
            if chi2 < min_chi2:
                min_chi2 = chi2
                best_idx = i
                
        # 执行合并
        bins[best_idx] = bins[best_idx] + bins[best_idx+1]
        del bins[best_idx+1]
    
    # 转换为分箱边界
    boundaries = [min(bin_) for bin_ in bins]
    boundaries.append(max(bins[-1]))
    
    return sorted(boundaries)

3.2 卡方分箱的调优技巧

  • 初始分箱:对于连续变量,可先进行等频预分箱(50-100箱)再合并
  • 稀疏箱处理:合并样本量小于5%的箱
  • 单调性修正:对WOE非单调的箱进行人工调整

4. 构建完整的分箱评估流水线

将分箱、WOE转换和IV评估整合为可复用的Pipeline,可以大幅提升特征工程效率。

4.1 自定义转换器实现

from sklearn.base import BaseEstimator, TransformerMixin

class WOETransformer(BaseEstimator, TransformerMixin):
    def __init__(self, binning_method='tree', n_bins=5):
        self.binning_method = binning_method
        self.n_bins = n_bins
        self.bin_dict = {}
        self.woe_dict = {}
        
    def fit(self, X, y):
        for col in X.columns:
            if self.binning_method == 'tree':
                bins = tree_binning(X[col], y, self.n_bins)
            else:
                bins = chi2_merge(X[col], y, self.n_bins)
                
            # 存储分箱边界
            self.bin_dict[col] = bins
            
            # 计算WOE
            binned = pd.cut(X[col], bins=bins, labels=False)
            woe_df = calculate_woe(
                pd.DataFrame({col: binned, 'target': y}),
                col, 'target'
            )
            self.woe_dict[col] = woe_df['woe'].to_dict()
            
        return self
    
    def transform(self, X):
        X_woe = X.copy()
        for col in X.columns:
            bins = self.bin_dict[col]
            woe_map = self.woe_dict[col]
            
            # 分箱并映射WOE值
            binned = pd.cut(
                X[col], 
                bins=bins, 
                labels=False,
                include_lowest=True
            )
            X_woe[col] = binned.map(woe_map)
            
        return X_woe

4.2 流水线集成示例

from sklearn.pipeline import Pipeline
from sklearn.linear_model import LogisticRegression

# 构建完整Pipeline
pipeline = Pipeline([
    ('woe_transform', WOETransformer(binning_method='chi2', n_bins=4)),
    ('model', LogisticRegression())
])

# 使用示例
pipeline.fit(X_train, y_train)
score = pipeline.score(X_test, y_test)

5. 不同分箱方法的业务场景选择

在实际金融风控项目中,分箱方法的选择需要考虑多种因素:

决策树分箱适用场景:

  • 需要强单调性的评分卡开发
  • 特征与目标存在明显非线性关系
  • 计算资源充足,特征数量较少

卡方分箱适用场景:

  • 保持原始数据分布更重要
  • 处理分类变量或混合类型特征
  • 需要快速处理大量特征

效果对比建议:

  1. 对同一特征尝试不同分箱方法
  2. 比较IV值变化和WOE曲线形态
  3. 最终选择在测试集上带来更高AUC的方法

在最近的一个消费信贷项目中,我们对比了三种分箱方法对30天逾期预测的效果:

特征等频分箱IV决策树分箱IV卡方分箱IV最终选择
收入0.120.180.15决策树
负债比0.080.220.19决策树
最近查询次数0.150.140.17卡方

从实际经验来看,决策树分箱在金融强监管场景中更受青睐,因为其产生的分箱规则更容易通过模型解释性审查。而卡方分箱在反欺诈等复杂模式识别任务中有时能发现更有价值的细分群体。

Logo

码道开发者社区,聚焦华为云码道 CodeArts 代码智能体,沉淀 Agent、Skill、鸿蒙开发实战内容,供开发者查阅资料、交流技术、分享工程实践

更多推荐