首页 > 其他 > 详细

Gini分箱

时间:2019-07-19 19:41:59      阅读:76      评论:0      收藏:0      [点我收藏+]

def calc_score_median(sample_set, var):
    '''
? ? 计算相邻评分的中位数,以便进行决策树二元切分
? ? param sample_set: 待切分样本
? ? param var: 分割变量名称
? ? '''
    var_list = list(np.unique(sample_set[var]))
    var_median_list = []
    for i in range(len(var_list)-1):
        var_median = (var_list[i]+var_list[i+1])/2
        var_median_list.append(var_median)
    return var_median_list

def choose_best_split(sample_set, var, min_sample):
    '''
? ? 使用CART分类决策树选择最好的样本切分点
? ? 返回切分点
? ? param sample_set: 待切分样本
? ? param var: 分割变量名称
? ? param min_sample: 待切分样本的最小样本量(限制条件)
    '''
#根据样本评分计算相邻不同分数的中间值
    score_median_list = calc_score_median(sample_set, var)
    median_len = len(score_median_list)
    sample_cnt = sample_set.shape[0]
    sample1_cnt = sum(sample_set["target"])
    sample0_cnt = sample_cnt - sample1_cnt
    Gini = 1-np.square(sample1_cnt/sample_cnt)-np.square(sample0_cnt/sample_cnt)
    bestGini = 0.0; bestSplit_point = 0.0; bestSplit_position = 0.0
    for i in range(median_len):
        left = sample_set[sample_set[var]<score_median_list[i]]
        right = sample_set[sample_set[var]>score_median_list[i]]
        left_cnt = left.shape[0]; right_cnt = right.shape[0]

        left1_cnt = sum(left["target"]); right1_cnt = sum(right["target"])
        left0_cnt = left_cnt - left1_cnt; right0_cnt = right_cnt - right1_cnt
        left_ratio = left_cnt/sample_cnt; right_ratio = right_cnt/sample_cnt
        if left_cnt<min_sample or right_cnt<min_sample:
            continue
        
        Gini_left = 1-np.square(left1_cnt/left_cnt) - np.square(left0_cnt/left_cnt)
        Gini_right = 1- np.square(right1_cnt/right_cnt) - np.square(right0_cnt/left_cnt)
        Gini_temp = Gini - (left_ratio*Gini_left + right_ratio*Gini_right)
        if Gini_temp > bestGini:
            bestGini = Gini_temp; bestSplit_point = score_median_list[i]
            if median_len>1:
                bestSplit_position = i/(median_len-1)
            else:
                bestSplit_position = i/median_len
        else:
            continue
    Gini = Gini-bestGini
    return bestSplit_point, bestSplit_position
        

def bining_data_split(sample_set, var, min_sample, split_list):
    """
    划分数据找到最优分割点list
    param sample_set: 待切分样本
    param var: 分割变量名称
    param min_sample: 待切分样本的最小样本量(限制条件)
    param split_list: 最优分割点list    
    """
    split, position = choose_best_split(sample_set, var, min_sample)
    if split !=0.0:
        split_list.append(split)
#? ?  根据分割点划分数据集,继续进行划分
    sample_set_left = sample_set[sample_set[var] < split]
    sample_set_right = sample_set[sample_set[var] >split]
#? ?  如果左子树样本量超过2倍最小样本量,且分割点不是第一个分割点,则切分左子树
    if len(sample_set_left) >= min_sample*2 and position not in [0.0,1.0]:
        bining_data_split(sample_set_left, var, min_sample, split_list)
    else:
        None
#? ?  如果右子树样本量超过2倍最小样本量,且分割点不是最后一个分割点,则切分右子树
    if len(sample_set_right) >= min_sample*2 and position not in [0.0,1.0]:
        bining_data_split(sample_set_right, var, min_sample, split_list)
    else:
        None


def get_bestsplit_list(sample_set, var):
    """
 ? ?根据分箱得到最优分割点list
? ? param sample_set: 待切分样本
? ? param var: 分割变量名称    
    """
#? ?  计算最小样本阈值(终止条件)
    min_df = sample_set.shape[0]*0.05
    split_list = []
#? ?  计算第一个和最后一个分割点
    bining_data_split(sample_set, var, min_df, split_list)
    return split_list



def bining_plot(sample,vars_name):
    try:
#        sample_df,name
#        sample =sample_df
        
        data = sample.copy()
        split_list = get_bestsplit_list(data, vars_name)
        split_l = [-np.inf]
        split_l.extend(split_list)
        split_l.append(np.inf)
        data[f"{vars_name}_bin"] = pd.cut(sample[vars_name],bins=split_l)
        data[f"{vars_name}_bin"] = data[f"{vars_name}_bin"].cat.add_categories(['null'])
        data[f"{vars_name}_bin"].fillna("null",inplace=True)
        
        data_count = pd.DataFrame(data.groupby(by = ['{}_bin'.format(vars_name)])['real_order_id'].count())
        data_count.columns = ['订单数']
        #放款数
        data_loan = pd.DataFrame(data.groupby(by = ['{}_bin'.format(vars_name)])['loan_flag'].sum())
        data_loan.columns = ['放款数']
        #逾期数
        data_overdue = pd.DataFrame(data.groupby(by = ['{}_bin'.format(vars_name)]).apply(lambda x : (x['status']==3).sum()))
        data_overdue.columns = ['逾期数']
        data_stat = pd.concat([data_count,data_loan,data_overdue],axis=1)
        data_stat.reset_index(inplace=True)
        data_stat.columns = ['bins','订单数','放款数','逾期数']
        data_stat = pd.concat([data_stat[data_stat.bins=='null'],data_stat[data_stat.bins!='null']],axis=0)
        #print(data_stat)
        data_stat.reset_index(inplace=True,drop=True)
        data_stat['订单占比'] = data_stat['订单数']/data_stat['订单数'].sum()
        data_stat['放款率'] = data_stat['放款数']/data_stat['订单数']
        data_stat['逾期率'] = data_stat['逾期数']/data_stat['放款数']
        data_stat['逾期率'].fillna(0,inplace=True)
        plt.figure(figsize=(15,8))
        plt.plot([ i for i in range(data_stat.shape[0])],data_stat['逾期率'])
        plt.bar([ i for i in range(data_stat.shape[0])],data_stat['订单占比'],color = 'orange')
        plt.xticks([ i for i in range(data_stat.shape[0]+1)],data_stat['bins'],rotation=50)
        data_stat['订单占比'] = data_stat['订单占比'].map(lambda x :str(np.round(x*100,2))+'%')
        data_stat['放款率'] = data_stat['放款率'].map(lambda x :str(np.round(x*100,2))+'%')
        data_stat['逾期率'] = data_stat['逾期率'].map(lambda x :str(np.round(x*100,2))+'%')
        print(tabulate(data_stat,headers=data_stat.columns,tablefmt='grid'))
        plt.show()
    except:
        error_list.append(vars_name)

Gini分箱

原文:https://www.cnblogs.com/lky520hs/p/11214986.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!