分箱_best-ks分箱

好久没有更新了,emm…

之前给大家分享过卡方分箱,想了解的可以点击下面链接。
卡方分箱

那么,今天给大家分享在评分卡中另外一种常见的分箱方法best-ks,首先我们先来了解一下,best-ks是如何分箱的。

1.分箱逻辑:

步骤:
  将变量排序后,计算出ks最大的值,即为切点,将数据分成2部分,分别对这2部分数据继续计算ks,找切点,直至达到箱子上限数

分箱后的KS值<=分箱前的KS值

2.实现代码:

################################### 计算ks值
def cal_ks(regroup,min_samples):
    '''
    args:        
        regroup:统计每个值的好、坏数,df
        min_samples:最小样本数
    return:
        ks_dict:
            ks_range:区间范围
            max_ks_cutoff:ks值最大的切点
            max_ks_value:最大的ks值        
    '''

    ks_range = str(regroup['feature_name'].agg(['min','max']).values.tolist()) # 最小值、最大值

    if (len(regroup) == 1) or (regroup['CntRec'].sum() < min_samples) or (regroup['CntBad'].sum()==0) or (regroup['CntGood'].sum()==0):
        # 出现以下四种情况将不进行分箱:只有一种值、总样本数较少、坏样本数为0、好样本数为0
        ks_dict = {ks_range:[-999999,-999999]}
    else:
        ###### 1.计算ks
        regroup.index = range(len(regroup))
        regroup['CntCumBad'] = regroup['CntBad'].cumsum()
        regroup['CntCumGood'] = regroup['CntGood'].cumsum()    
        regroup['CntCumBadRate'] = regroup['CntCumBad'] / regroup['CntBad'].sum()
        regroup['CntCumGoodRate'] = regroup['CntCumGood'] / regroup['CntGood'].sum()
        regroup['KS'] = abs(regroup['CntCumBadRate'] - regroup['CntCumGoodRate'])

        ###### 2.找出ks最大的值、切点、范围
        max_ks_value = regroup['KS'].max() # ks值
        max_ks_cutoff = regroup.loc[regroup['KS'].argmax(),'feature_name'] # 切点                        
        ks_dict = {ks_range:[max_ks_cutoff,max_ks_value]}

    return ks_dict


################################### 挑选出best-ks的切点
def best_ks_cut_bin(data,cols_num,label,max_interval=5,min_samples_rate=0.05):
    '''
    args:
        data:数据源,df
        cols_num:数值型字段,列表
        label:标签,string
        max_interval=5:最大分箱数,int
        min_samples_rate=0.05:每个箱子的最小样本数
    return:
        cols_num_points:各数值变量的切点,字典
    '''
    cols_num_points = {}

    for col in cols_num:
        print(col)

        if len(data[col].unique()) < max_interval:  # 如果数据的有限值个数 < 最大分箱数,则不分箱,反之分箱
            col_points = data[col].unique()

        else:
            min_samples = len(data)*min_samples_rate

            # 统计每个值的好、坏数
            regroup = data.groupby([col])[label].agg(['count','sum']).reset_index().rename(columns={col:'feature_name','count':'CntRec','sum':'CntBad'})
            regroup['CntGood'] = regroup['CntRec'] - regroup['CntBad']

            # 第一次划分切点        
            ks_dict = cal_ks(regroup,min_samples)       
            col_points = [list(ks_dict.values())[0][0]]        

            # 循环划分
            while len(col_points) < max_interval-1:
                best_ks_value = -999999
                best_ks_cutoff = -999999
                i = 0
                # 对于每个区间进行再次划分
                while i <= len(col_points):
                    ###### 1.提取每个区间内的数据
                    if i==0:
                        regroup_per = regroup[regroup['feature_name'] <= col_points[i]]
                    elif i==len(col_points):
                        regroup_per = regroup[regroup['feature_name'] > col_points[i-1]]
                    else:
                        regroup_per = regroup[(regroup['feature_name'] > col_points[i-1]) & (regroup['feature_name'] <= col_points[i])]

                    ###### 2.判断该区间有没有计算过ks,如果计算过,直接提取相应的ks,反之计算
                    ks_range = str(regroup_per['feature_name'].agg(['min','max']).values.tolist()) # 区间范围                
                    if ks_range in ks_dict.keys():
                        max_ks_cutoff, max_ks_value = ks_dict[ks_range]                        
                    else:                    
                        ks_dict_i = cal_ks(regroup_per,min_samples)
                        max_ks_cutoff, max_ks_value = list(ks_dict_i.values())[0]                    
                        ks_dict.update(ks_dict_i)

                    ###### 3.提取ks最大的切点
                    if max_ks_value > best_ks_value:
                        best_ks_cutoff, best_ks_value = max_ks_cutoff, max_ks_value 

                    i = i + 1 # 循环计算下一个区间的ks

                # 循环结束后,添加ks最大的切点
                col_points.append(best_ks_cutoff)
                col_points = sorted(col_points)

            # 切点结果处理
            col_points = list(set(col_points) - set([-999999]))

        cols_num_points[col] = col_points

    return cols_num_points

详细内容请关注我的公众号~
在这里插入图片描述

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值