-
-
[原创]机器学习基础-特征工程2分箱
-
发表于: 2025-9-15 21:19 675
-
变量分箱方式详解及金融风控应用指南
分箱核心目的:将连续变量(年龄、收入等)转化为离散区间,提升模型稳定性、捕捉非线性关系、降低异常值影响。在金融风控中,分箱直接影响评分卡效果和业务解释性。
一、分箱方法全解析(附金融场景对比)
- 1、等宽分箱(EQUAL WIDTH)
原理:按数值范围均匀切分,每个箱子宽度相同
公式:箱宽 = (最大值 - 最小值) / 箱数
金融案例:
- 收入分箱(单位:万元):
[0-10), [10-20), [20-30), [30+]
Python实现:
1 2 3 | import pandas as pddata = [8, 15, 22, 35, 12, 28]pd.cut(data, bins=[0,10,20,30,40], labels=["低收","中收","高收","超高收"]) |
输出:[低收, 中收, 高收, 超高收, 中收, 高收]
优点:简单直观
缺点:易受异常值影响(如收入1000万会拉宽区间)
金融适用:分布均匀的特征(如年龄)
- 2、 等频分箱(EQUAL FREQUENCY)
原理:按样本量切分,每个箱子样本数相同
公式:箱边界 = 分位数点
金融案例:
- 贷款金额分箱(1000个样本分5箱):
箱1:金额最低的200人 → "小额"
箱5:金额最高的200人 → "大额"
Python实现:
1 | pd.qcut(data, q=4, labels=["Q1","Q2","Q3","Q4"]) # 分4箱 |
输出:每个箱样本量≈25%
优点:抗异常值,保证样本均衡
缺点:相同数值可能分到不同箱
金融适用:收入、负债比等偏态分布特征
- 3、 决策树分箱(TREE-BASED)
原理:用CART/ID3等树模型寻找最优分裂点
金融案例:用年龄预测违约率
Python实现:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 | from sklearn.tree import DecisionTreeClassifierimport random#创建表hangshu=100000df=pd.DataFrame({ 'age':[random.randint(20, 60) for i in range(hangshu)], 'default': [random.randint(0,1) for i in range(hangshu)] })# 用树模型找分箱点def optimal_binning_boundary(x, y,q=3): """ 使用决策树获取最优分箱边界值 :param x: 特征变量 :param y: 目标变量 :return: 分箱边界值列表 """ boundary = [] # 存储分箱边界值 x = x.fillna(-1).values # 填充缺失值 y = y.values # 创建决策树模型 clf = DecisionTreeClassifier( criterion='entropy', # 使用信息熵最小化准则 max_leaf_nodes=q, # 分几箱 min_samples_leaf=0.05 # 叶子节点最小样本占比 ) clf.fit(x, y) # 训练决策树 # 获取决策树的节点信息 n_nodes = clf.tree_.node_count children_left = clf.tree_.children_left children_right = clf.tree_.children_right threshold = clf.tree_.threshold # 遍历非叶子节点,提取分箱边界 for i in range(n_nodes): if children_left[i] != children_right[i]: # 非叶子节点 boundary.append(threshold[i]) # 排序并添加最小值和最大值 boundary.sort() min_x = x.min() max_x = x.max() + 0.1 # 增加0.1以包含最大值 boundary = [min_x] + boundary + [max_x] return sorted(list(set(boundary)))bins_list=optimal_binning_boundary(df[['age']], df['default']) |
优点:直接关联目标变量,预测能力强
缺点:可能过拟合
金融适用:所有关键特征(尤其与违约强相关)
- 4、卡方分箱(CHI-MERGE)
原理:基于卡方检验合并相似区间
步骤:
- 初始每个值一箱
- 计算相邻箱违约率卡方值
- 合并卡方值最小的箱(违约率最相似)
金融公式:
χ2=∑预期违约(实际违约−预期违约)2
停止条件:卡方值 > 阈值(如3.84对应p=0.05)
金融案例:优点:统计驱动,业务可解释性强收入区间 正常用户 违约用户 卡方值 [0-10万) 100 20 1.2 → 合并 [10-20万) 120 22 [20-30万) 200 10 8.1 → 保留
缺点:计算复杂
金融适用:信用评分卡开发
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 | import numpy as npimport pandas as pdfrom scipy.stats import chi2# 计算2*2列联表的卡方值def get_chi2_value(arr): rowsum = arr.sum(axis=1) # 对行求和,大小为M的数组,是当前分箱情况下,每个箱的样本数量 colsum = arr.sum(axis=0) # 对列求和,大小为N_class的数组,每个元素就是每个类别的样本数量 n = arr.sum() emat = np.array([i * j / n for i in rowsum for j in colsum]) #计算每个区间下每个类别样本数量的期望值,大小为M*N_class arr_flat = arr.reshape(-1) arr_flat = arr_flat[emat != 0] # 剔除了期望为0的值,不参与求和计算,不然没法做除法! emat = emat[emat != 0] # 剔除了期望为0的值,不参与求和计算,不然没法做除法! E = (arr_flat - emat) ** 2 / emat return E.sum()# 自由度以及分位点对应的卡方临界值def get_chi2_threshold(percents, nfree): return chi2.isf(percents, df=nfree)# 计算卡方切分的切分点def get_chimerge_cutoff(ser, tag, max_groups=None, threshold=None): freq_tab = pd.crosstab(ser, tag) cutoffs = freq_tab.index.values # 保存每个分箱的下标 freq = freq_tab.values # [M,N_class]大小的矩阵,M是初始箱体的个数,N_class是目标变量类别的个数 while True: min_value = None #存放所有对相邻区间中卡方值最小的区间的卡方值 min_idx = None #存放最小卡方值的一对区间中第一个区间的下标 for i in range(len(freq) - 1): chi_value = get_chi2_value(freq[i:(i + 2)]) #计算第i个区间和第i+1个区间的卡方值 if min_value == None or min_value > chi_value: min_value = chi_value min_idx = i if (max_groups is not None and max_groups < len(freq)) or ( threshold is not None and min_value < get_chi2_threshold(threshold, len(cutoffs)-1)): tmp = freq[min_idx] + freq[min_idx + 1] #合并卡方值最小的那一对区间 freq[min_idx] = tmp freq = np.delete(freq, min_idx + 1, 0) #删除被合并的区间 cutoffs = np.delete(cutoffs, min_idx + 1, 0) else: break return cutoffsnp.random.seed(42)n = 10000age = np.random.normal(40, 15, n) # 年龄均值40,标准差15default = (age > 50) & (np.random.rand(n) < 0.7) # 年龄大且随机违约# 转为 DataFramedf = pd.DataFrame({'age': age, 'default': default.astype(int)})cutoffs = get_chimerge_cutoff( ser=age, tag=default, max_groups=10, # 最多分 5 个箱 threshold=0.05 # 显著性水平(p值))print("最优分箱切分点(边界):")print(cutoffs) |
- 5、最优分箱(IV/WOE分箱)
金融风控最常用方法!
核心指标:
- WOE(证据权重):
WOE=ln(违约占比正常占比) - IV(信息值):
IV=∑(正常占比−违约占比)×WOE
分箱流程:
- 粗分箱(如等频10箱)
- 计算每箱WOE
- 合并WOE相似的箱(|ΔWOE|<0.05)
- 检查单调性(如收入↑ → WOE↑)
- 最大化IV值
金融标准:
- IV < 0.02:无预测力
- IV > 0.3:强预测力
Python实现:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | from optbinning import OptimalBinning# 初始化 OptimalBinning 对象optb = OptimalBinning( name="age", # 特征名称(字符串) dtype="numerical", # 指定为数值型变量 max_n_bins=5, # 最大分箱数 min_bin_size=0.05, # 每个分箱最小占比(可选,防止过小分箱) solver="mip" # 使用混合整数规划求解器(推荐,比“auto”更稳定))optb.fit(df['age'], df['default'])print(optb.status)print(optb.splits)table=optb.binning_table.build() |
二、金融风控最常用分箱方法TOP3
最优分箱(IV/WOE)
使用率:>80%的评分卡开发
原因:
- 直接量化特征预测能力(IV值)
- WOE转换提升逻辑回归效果
- 满足监管要求(可解释性强)
典型场景: - 信用卡申请评分
- 小微企业贷风控
决策树分箱
使用率:60%的机器学习模型
原因:
- 自动化寻找关键分裂点
- 与GBDT/XGBoost模型兼容性好
典型场景: - 反欺诈模型
- 早期预警系统
卡方分箱
使用率:40%的存量客户管理
原因:
- 统计显著性检验
- 业务人员易理解
典型场景:- 客户分层运营
- 额度调整策略
三、金融分箱核心原则
业务逻辑优先
- 年龄分箱参考生命周期:18-25(学生), 25-35(职场新人), 35-50(黄金期), 50+(退休)
单调性强制约束
- 强制收入分箱WOE单调上升
1 | optb = OptimalBinning(monotonic_trend="ascending") |
- 特殊值独立分箱
- 缺失值单独成箱(如"收入_未知")
- 异常值归入"极高/极低"箱
- 箱数控制:4-6箱最佳(避免信息碎片化)
最后于 2025-9-15 21:21
被charley_Lu编辑
,原因:
赞赏
他的文章
- [原创]机器学习基础-特征工程2分箱 676
- [原创]机器学习基础-特征工程1 375
- [原创]机器学习-金融风控1 408
- [原创]机器学习认知-3 350
- [原创]机器学习认知-2 408
赞赏
雪币:
留言: