评分卡

【算法】一篇入门之-决策树分箱

作者 : 老饼 发表日期 : 2022-11-28 12:19:08 更新日期 : 2024-12-20 03:13:45
本站原创文章,转载请说明来自《老饼讲解-机器学习》www.bbbdata.com



决策树分箱是一种有监督分箱算法,它借助决策树模型对连续变量进行分箱

本文讲解决策树分箱用于连续变量的分箱方法、算法流程以及相关参数,并展示具体的代码实现

通过本文,可以快速了解什么是决策树分箱算法,以及如何使用决策树分箱对来对连续变量进行分箱





    01. 什么是决策树分箱    





本节讲解什么是决策树分箱,以及展示一个决策树分箱例子





     什么是决策树分箱    


决策树分箱是对连续变量进行变量分箱的一种方法,它属于有监督分箱,即需要有y值
 由于决策树分箱要使用决策树模型,如果不熟悉决策树可以参考文章《决策树与CART决策树
简单来说,决策树分箱就是利用决策树模型进行分箱
它将需要分箱的单个变量与y进行CART决策树建模,将最终的树分割结果作为分箱结果
 如下,使用x、y构建决策树,叶子节点就是分箱的结果
 
什么是决策树分箱 
 最后得到三个分箱:【<=5.45 】、(5.45,6.15】、【>6.15】





     决策树分箱-实例讲解    


 以下是iris数据:
 iris数据
 
要对x1进行分箱,只需要将x1与类别建立决策树,如下
 决策树建模结果
 可以看到,只用x1预测类别时,x1的切割点为 [ 5.45,4.85,6.15,5.05,5.75,6.85,6.45]
 整理后就得到以下分箱结果:
 决策树分箱结果







     02. 决策树分箱-算法流程与代码     




本节展示决策树分箱的算法流程




    决策树分箱流程    


决策树分箱的算法流程如下: 
1.  将要分箱的x和对应的y,放到决策树中           
2.  根据目标分箱个数,调整相关的决策树参数    
3.  训练决策树                                                   
4.  提取决策树对x的分割点作为分箱结果            
 备注:最终决策树的每个叶子节点,就是一个分箱
     决策树分箱的关键参数     
由于在决策树分箱中,最终决策树的每个叶子节点,就是一个分箱
因此,需要通过调整参数来获得想要的分箱个数
 在sklearn中,影响分箱个数(叶子节点)的参数有: 
min_samples_leaf               :叶子节点最小样本数         
min_samples_split              :节点分枝最小样本个数      
max_depth                          :树分枝的最大深度             
min_weight_fraction_leaf   :叶子节点最小权重和         
min_impurity_decrease      :节点分枝最小纯度增长量  
max_leaf_nodes                  :最大叶子节点数                
 ccp_alpha                             :CCP剪枝系数                    
 备注:更多关于决策树参数的内容,可以参考《sklearn决策树参数详解





    决策树分箱-代码实现    


下面用python实现决策树分箱,它只适用于连续变量
具体代码实现如下:
# -*- coding: utf-8 -*-
"""
决策树分箱
本代码由《老饼讲解-机器学习》www.bbbdata.com编写
"""
from sklearn.datasets import load_iris
from sklearn import tree
import pandas as pd
import numpy as np

# 将类别转为类别矩阵(one-hot格式)
def class2Cmat(y):
    c_name = list(np.unique(y))                                             # 类别名称
    c_num  = len(c_name)                                                    # 类别个数
    cMat   = np.zeros([len(y),c_num])                                       # 初始化类别矩阵
    for i in range(c_num):                                                  
        cMat[y==c_name[i],i] = 1                                            # 将样本对应的类别标为1
    c_name = [str(i) for i in c_name]                                       # 类别名称统一转为字符串类型
    return cMat,c_name                                                      # 返回one-hot类别矩阵和类别名称

# 将切割点转换成分箱说明
def getBinDesc(bin_cut):
    bin_first = ['<='+str(bin_cut[0])]                                      # 第一个分箱
    bin_last  = ['>'+str(bin_cut[-1])]                                      # 最后一个分箱
    bin_desc  = ['('+str(bin_cut[i])+','+str(bin_cut[i+1])+']'             
                 for i in range(len(bin_cut)-1)]                            # 中间的分箱说明
    bin_desc  = bin_first+bin_desc+bin_last                                 # 拼接首尾分箱说明   
    return  bin_desc

# 计算分箱详情
def statBinNum(x,y,bin_cut):
    bin_desc       = getBinDesc(bin_cut)                                    # 获取分箱说明
    c_mat,c_name   = class2Cmat(y)                                          # 将类别转为one-hot类别矩阵
    df             = pd.DataFrame(c_mat,columns=c_name,dtype=int)           # 将类别矩阵转为dataFrame
    df['cn']       = 1                                                      # 预设一列1,方向后面统计
    df['grp']      = 0                                                      # 初始化分组序号
    df['grp_desc'] = ''                                                     # 初始化分箱说明
																           
    # 计算各个样本的分组序号与分箱说明                                     
    df.loc[x<=bin_cut[0],'grp']=0                                           # 第0组样本的序号 
    df.loc[x<=bin_cut[0],'grp_desc']  =bin_desc[0]                          # 第0组样本的分箱说明 
    for i in range(len(bin_cut)-1):                                         # 逐区间计算分箱序号与分箱说明
        df.loc[(x>bin_cut[i])&(x<=bin_cut[i+1]),'grp']     = i+1   
        df.loc[(x>bin_cut[i])&(x<=bin_cut[i+1]),'grp_desc']= bin_desc[i+1]
															               
    df.loc[x>bin_cut[-1],'grp']=len(bin_cut)                                # 最后一组样本的序号 
    df.loc[x>bin_cut[-1],'grp_desc']=bin_desc[-1]                           # 最后一组样本的分箱说明 
    
    # 按组号聚合,统计出每组的总样本个数和各类别的样本个数
    col_dict     = {'grp':'max','grp_desc':'max','cn':'sum'}                # 按组号聚合
    col_dict.update({col:'sum' for col in c_name})                          #
    df           = df.groupby('grp').agg(col_dict).reset_index(drop=True)   # 
    return df                                                               # 返器分箱结果
#-----以上部分只用于统计分箱结果详情,与决策树分箱算法无关--------

# -----决策树分箱主函数----------
def treeMerge(x,y,min_samples=10):
    clf       = tree.DecisionTreeClassifier(min_samples_leaf=min_samples)    # sk-learn的决策树模型
    clf       = clf.fit(pd.DataFrame(x), y)                                  # 用数据训练树模型构建()
    bin_cut   = clf.tree_.threshold[clf.tree_.children_left>0]               # 提取切割点
    bin_cut.sort()                                                           # 切割点进行排序
    bin_desc = getBinDesc(bin_cut)                                           # 生成分箱说明
    return bin_cut,bin_desc                                                  
																		     
#----------使用Demo--------------                                            
# 加载数据                                                                   
iris = load_iris()                                                           # 加载iris数据
x    = iris.data[:,0]                                                        # 取第0个变量作为分箱变量
y    = iris.target                                                           # 类别标签
bin_cut,bin_desc = treeMerge(x,y,min_samples=15)                             # 用决策树进行分箱
bin_stat         = statBinNum(x,y,bin_cut)                                   # 计算各个分箱的样本个数
																		     
# 打印结果                                                                   
print('切割点:',bin_cut)                                                     # 打印切割点
print('分箱说明:',bin_desc)                                                  # 打印分箱说明
print('---------分箱统计----------')                                         
print(bin_stat)                                                              # 打印分箱统计
代码运行结果如下:
 决策树分箱代码运行结果
从结果中可以看到,它把变量分成了8个组,共7个切割点






好了,以上就是决策树分箱的原理与具体代码实现了~








 End 




联系老饼