【有监督分箱】方法一:卡方分箱

本文介绍了有监督分箱中的卡方分箱方法,详细讲解了卡方分箱的原理、步骤、分箱的用处以及评估指标。通过卡方检验判断相邻区间的相似性,实现数据离散化,适用于金融行业的评分卡建模。同时讨论了分箱过程中的注意事项,如避免因分箱过细导致的WOE计算问题。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1.前言

评分卡建模在金融行业应用得比较广泛,比如对客户的信贷诚信度进行评分。在建模过程中,对连续变量的分箱是一个必不可少的过程。正好我最近的项目也是要做一个积分卡,因此想对分箱做一个较全面的总结。

2.定义

何谓分箱,简单地说,分箱就是将连续变量离散化,将多状态的离散变量合并成少状态。

3.分箱的用处

  1. 离散特征的增加和减少都很容易,易于模型的快速迭代;
  2. 稀疏向量内积乘法运算速度快,计算结果方便存储,容易扩展;
  3. 列表内容离散化后的特征对异常数据有很强的鲁棒性:比如一个特征是年龄>30是1,否则0。如果特征没有离散化,一个异常数据“年龄300岁”会给模型造成很大的干扰;
  4. 列表内容逻辑回归属于广义线性模型,表达能力受限;单变量离散化为N个后,每个变量有单独的权重,相当于为模型引入了非线性,能够提升模型表达能力,加大拟合;
  5. 离散化后可以进行特征交叉,由M+N个变量变为M*N个变量,进一步引入非线性,提升表达能力;
  6. 列表内容特征离散化后,模型会更稳定,比如如果对用户年龄离散化,20-30作为一个区间,不会因为一个用户年龄长了一岁就变成一个完全不同的人。当然处于区间相邻处的样本会刚好相反,所以怎么划分区间是门学问;
  7. 特征离散化以后,起到了简化了逻辑回归模型的作用,降低了模型过拟合的风险。 可以将缺失作为独立的一类带入模型。
  8. 将所有变量变换到相似的尺度上。

4.分箱方法

分箱方法分为无监督分箱和有监督分箱。常用的无监督分箱方法有等频分箱,等距分箱和聚类分箱。有监督分箱主要有best-ks分箱和卡方分箱。基于我的项目中重点应用了卡方分箱,所以这里重点对卡方分箱做些总结。

5.卡方分箱的原理

卡方分箱是自底向上的(即基于合并的)数据离散化方法。它依赖于卡方检验:具有最小卡方值的相邻区间合并在一起,直到满足确定的停止准则。
基本思想:对于精确的离散化,相对类频率在一个区间内应当完全一致。因此,如果两个相邻的区间具有非常类似的类分布,则这两个区间可以合并;否则,它们应当保持分开。而低卡方值表明它们具有相似的类分布。
分箱步骤:
这里写图片描述
这里需要注意初始化时需要对实例进行排序,在排序的基础上进行合并。

卡方阈值的确定:
  根据显著性水平和自由度得到卡方值
  自由度比类别数量小1。例如:有3类,自由度为2,则90%置信度(10%显著性水平)下,卡方的值为4.6。

阈值的意义
  类别和属性独立时,有90%的可能性,计算得到的卡方值会小于4.6。
  大于阈值4.6的卡方值就说明属性和类不是相互独立的,不能合并。如果阈值选的大,区间合并就会进行很多次,离散后的区间数量少、区间大。

6.分完箱之后评估指标

分为箱之后,需要评估。在积分卡模型中,最常用的评估手段是计算出WOE和IV值。对于WOE和IV值的含义,我推荐博客:
https://blog.csdn.net/kevin7658/article/details/50780391
对于其计算方式,我后面代码会直接给出。

7.直接代码

def Chi2(df, total_col, bad_col,overallRate):
    '''
     #此函数计算卡方值
     :df dataFrame
     :total_col 每个值得总数量
     :bad_col 每个值的坏数据数量
     :overallRate 坏数据的占比
     : return 卡方值
    '''
    df2=df.copy()
    df2['expected']=df[total_col].apply(lambda x: x*overallRate)
    combined=zip(df2['expected'], df2[bad_col])
    chi=[(i[0]-i[1])**2/i[0] for i in combined]
    chi2=sum(chi)
    return chi2

#基于卡方阈值卡方分箱,有个缺点,不好控制分箱个数。
def ChiMerge_MinChisq(df, col, target, confidenceVal=3.841):
    '''
    #此函数是以卡方阈值作为终止条件进行分箱
    : df dataFrame
    : col 被分箱的特征
    : target 目标值,是0,1格式
    : confidenceVal  阈值,自由度为1, 自信度为0.95时,卡方阈值为3.841
    : return 分箱。
    这里有个问题,卡方分箱对分箱的数量没有限制,这样子会导致最后分箱的结果是分箱太细。
    '''
    #对待分箱特征值进行去重
    colLevels=set(df[col])
    
    #count是求得数据条数
    total=df.groupby([col])[target].count()
   
    total=pd.DataFrame({
   'total':total})
 
    #sum是求得特征值的和
    #注意这里的target必须是0,1。要不然这样求bad的数据条数,就没有意义,并且bad是1,good是0。
    bad=df.groupby([col])[target].sum()
    bad=pd.DataFrame({
   'bad':bad})
    #对数据进行合并,求出col,每个值的出现次数(total,bad)
    regroup=total.merge(bad, left_index=True, right_index=True, how='left')
    regroup.reset_index(level=0, inplace=True)
  
    #求出整的数据条数
    N=sum(regroup['total'])
    #求出黑名单的数据条数
    B=sum(regroup['bad'])
    overallRate=B*1.0/N
    
    #对待分箱的特征值进行排序
    colLevels=sorted(list(colLevels))
    groupIntervals=[[i] for i in colLevels]
   
    groupNum=len(groupIntervals)
    while(1):
        if len(groupIntervals) == 1:
            break
        chisqList=[]
        for interval in groupIntervals:
            df2=regroup.loc[regroup[col].isin(interval)]
            chisq=Chi2(df2, 'total', 'bad', overallRate)
            chisqList.append(chisq)

        min_position=chisqList.index(min(chisqList))
    
        if min(chisqList) >= confidenceVal:
            break
        
        if min_position==0:
            combinedPosition=1
        elif min_position== groupNum-1:
            combinedPosition=min_position-1
        else:
            if chisqList[min_position-1]<=chisqList[min_position + 1]:
                combinedPosition=min_position-1
            else:
                combinedPosition=min_position+1
        groupIntervals[min_position]=groupIntervals[min_position]+groupIntervals[c
### 分箱算法概述 分箱种常见的数据预处理技术,用于将连续型变量离散化或将类别型变量重新编码。通过分箱可以减少噪声的影响、提高模型的稳定性以及更好地保留原始数据的信息[^1]。 #### 最佳分箱(Optimal Binning) 最佳分箱是指利用特定的统计量或算法来划分区间,使得每个箱子内的样本尽可能同质,而不同箱子之间则具有显著差异。这种方法能够有效提升模型性能,但也伴随着较高的计算成本和时间消耗。 #### 分箱 分箱种常用的分箱方法,其核心思想是比较相邻两个区间的分布差异。如果两者的分布相似,则将其合并;反之则分开。具体实现可以通过如下代码完成: ```python def cal_chi2(df, all_bad_rate): """ 计算每对相邻区间的值 参数: df (pd.DataFrame): 输入的数据框,需包含各组的好坏比例信息 all_bad_rate (float): 整体的坏客户比率 返回: float: 当前分割下的值 """ chi_values = [] for i in range(len(df)-1): group_i = df.iloc[i] group_ip1 = df.iloc[i+1] expected_good_i = (group_i['total'] * (1-all_bad_rate)) expected_bad_i = (group_i['total'] * all_bad_rate) observed_good_i = group_i['good'] observed_bad_i = group_i['bad'] chi_group_i = ((observed_good_i - expected_good_i)**2 / expected_good_i + (observed_bad_i - expected_bad_i)**2 / expected_bad_i) expected_good_ip1 = (group_ip1['total'] * (1-all_bad_rate)) expected_bad_ip1 = (group_ip1['total'] * all_bad_rate) observed_good_ip1 = group_ip1['good'] observed_bad_ip1 = group_ip1['bad'] chi_group_ip1 = ((observed_good_ip1 - expected_good_ip1)**2 / expected_good_ip1 + (observed_bad_ip1 - expected_bad_ip1)**2 / expected_bad_ip1) chi_values.append(chi_group_i + chi_group_ip1) return min(chi_values), chi_values.index(min(chi_values)) chi_value, index_to_merge = cal_chi2(chi_df, all_bad_rate)[^2] ``` 上述函数实现了基于检验的分箱逻辑,其中`cal_chi2`负责评估当前分箱案的质量并决定哪些区间应该被合并。 #### WOE分箱 权重证据(Weight of Evidence, WOE)分箱广泛应用于金融领域特别是信用评分建模中。它不仅关注如何合理分配数值到各个箱子内,还强调这些箱子间的关系应当满足单调约束条件。这意味着随着自变量增大,对应的WOE要么持续上升要么不断下降[^3]。 以下是简单的WOE转换示例: ```python import numpy as np def compute_woe(iv_df): iv_df["woe"] = np.log((iv_df["goods_ratio"])/(iv_df["bads_ratio"])) return iv_df # 调用该函数即可得到带有WOE列的新表 result_with_woe = compute_woe(input_data_frame) ``` --- ###
评论 20
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值