美文网首页
快速分箱方法

快速分箱方法

作者: 这是沸羊羊的干爹 | 来源:发表于2018-08-02 18:00 被阅读0次

python 分箱的一种方法


2018.08.02


R语言中有smbining可以进行最优分箱,python中分箱如果既要考虑箱体个数,分箱后信息量大小,也要考虑单调性等其他因素。
这里给出一种简单的通过IV值来选择如果分箱的方法。
下面是按照分位数来分的,还可以按照卡房分箱,决策树分箱等。
参照toad(由厚本金融开发的较标准的评分卡开发开源包)的分箱方式。

class CUT_():
    def __init__(self,data,catecory,target):
        self.data = copy.deepcopy(data)
        self.catedat = self.data[catecory]
        self.catedat = self.catedat.map(float)
        self.y = self.data['y'].map(float)
        self.y = self.y.map(int)
        self.catecory = catecory
        self.target = target
    @staticmethod    
    def ivsum(data,y,binlist,catecory,target):
        tep_iv = OrderedDict()
        dat = data.map(lambda x:float(x))
        dat_tem = dat[dat!='nan']
        bins = binlist
        datcut = pd.cut( dat_tem,   
                         [-float("inf")]+bins+[float("inf")])  
        dat = pd.concat([datcut,dat[dat=='nan']],axis=0)
        dat = dat.sort_index()
        dat = dat.map(str)
        labels = list(set(dat))         
        dat2 = pd.concat([dat,y],axis=1)
        dat2[target] = dat2[target].map(str)
        C=(dat2[target]=='0').sum()
        D=(dat2[target]=='1').sum()
        for j in labels:
            temdat=list(dat2[dat2[catecory]==j][target])
            if len(temdat)>0:
                A=len([x for x in temdat if x =='0'])
                B=len([x for x in temdat if x =='1'])
                if A!=0 and B!=0:
                    iv=round((B/D-A/C)*(log((B/D)/(A/C))),6)
                    tep_iv.update({j:iv}) 
                if A==0 and B!=0:
                    A=A+1
                    iv=round((B/D-A/C)*(log((B/D)/(A/C))),6)
                    tep_iv.update({j:iv}) 
                if B==0 and A!=0:
                    B=B+1
                    iv=round((B/D-A/C)*(log((B/D)/(A/C))),6)
                    tep_iv.update({j:iv}) 
                if B==0 and A==0:
                    B=B+1
                    A=A+1
                    iv=round((B/D-A/C)*(log((B/D)/(A/C))),6)
                    tep_iv.update({j:iv}) 
            if len(temdat)==0:
                tep_iv.update({j:np.nan}) 
        dataivsum = sum([x for x in tep_iv.values() if pd.isnull(x)==0])
        minrate = dat2[catecory].value_counts().min()/dat2.shape[0]
        return dataivsum,labels,bins,minrate
    def bin_fun(self):
        tem1 = self.catedat[self.catedat!='nan'].sort_values()
        tem2 = self.catedat[(self.catedat!=''nan'')&(self.catedat!=-0)].sort_values()
        var_set1 = pd.Series(sorted(list(set(tem1))))
        var_set2 = pd.Series(sorted(list(set(tem2))))
        cut_ = {'c1':[tem1.quantile(.25),tem1.quantile(.5),tem1.quantile(.75)],
        'c2' : [tem1.quantile(.33),tem1.quantile(.66)],
        'c3' : [tem1.quantile(.5)],
        'c4' : [0],
        'c5' : sorted([0,tem2.quantile(.25),tem2.quantile(.5),tem2.quantile(.75)]),
        'c6' : sorted([0,tem2.quantile(.33),tem2.quantile(.66)]),
        'c7': sorted([0,tem2.quantile(.5)]),
        'c8':  sorted([var_set1.quantile(.25),var_set1.quantile(.5),var_set1.quantile(.75)]),
        'c9' : sorted([var_set1.quantile(.33),var_set1.quantile(.66)]),
        'c10' : sorted([var_set1.quantile(.5)]),
        'c11' : [0],
        'c12' : sorted([0,var_set2.quantile(.25),var_set2.quantile(.5),var_set2.quantile(.75)]),
        'c13' : sorted([0,var_set2.quantile(.33),var_set2.quantile(.66)]),
        'c14': sorted([0,var_set2.quantile(.5)]),
        'c15':[ mode(tem1)[0][0]], 'c16':[ mode(tem2)[0][0]], 
        'c17':[tem1.mean()],
        'c18': [tem2.mean()], 
        'c19':[var_set1.mean()],
        'c20':[ var_set2.mean()]}
        # 这里用的分位数对应的值来分,还可以尝试其他不同的分法,
        # 分法越多,相对最优的分箱效果越好。当然越来越慢。。。笨办法就没有考虑其他的了
        self.iv_ = dict()
        for i in cut_.keys():
            if len(cut_[i])!=len(set(cut_[i])):
                pass
            else:
                dataivsum,labels,bins,minrate = self.ivsum(self.catedat,self.y,cut_[i],self.catecory,self.target)
                if minrate<0.005:
                # 如果最小类的比例小于千分之五,则不输出
                    pass
                else:
                    self.iv_[i] = dataivsum
        best = [k for k,v in self.iv_.items() if v==max(self.iv_.values())]
        ## 输出IV值最大的分法
        if len(best)>0:
            self.best_cut = cut_[best[0]]
        else:
            print('找不到最优分法')
            self.best_cut = [0]
    def main(self):
        self.bin_fun()
        return self.iv_,self.best_cut

相关文章

网友评论

      本文标题:快速分箱方法

      本文链接:https://www.haomeiwen.com/subject/gwusvftx.html