python实现连续变量最优分箱详解--CART算法


Posted in Python onNovember 22, 2019

关于变量分箱主要分为两大类:有监督型和无监督型

对应的分箱方法:

A. 无监督:(1) 等宽 (2) 等频 (3) 聚类

B. 有监督:(1) 卡方分箱法(ChiMerge) (2) ID3、C4.5、CART等单变量决策树算法 (3) 信用评分建模的IV最大化分箱 等

本篇使用python,基于CART算法对连续变量进行最优分箱

由于CART是决策树分类算法,所以相当于是单变量决策树分类。

简单介绍下理论:

CART是二叉树,每次仅进行二元分类,对于连续性变量,方法是依次计算相邻两元素值的中位数,将数据集一分为二,计算该点作为切割点时的基尼值较分割前的基尼值下降程度,每次切分时,选择基尼下降程度最大的点为最优切分点,再将切分后的数据集按同样原则切分,直至终止条件为止。

关于CART分类的终止条件:视实际情况而定,我的案例设置为 a.每个叶子节点的样本量>=总样本量的5% b.内部节点再划分所需的最小样本数>=总样本量的10%

python代码实现:

import pandas as pd
import numpy as np
 
#读取数据集,至少包含变量和target两列
sample_set = pd.read_excel('/数据样本.xlsx')
 
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

var表示需要进行分箱的变量名,返回一个样本变量中位数的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 / right_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

min_sample 参数为最小叶子节点的样本阈值,如果小于该阈值则不进行切分,如前面所述设置为整体样本量的5%

返回的结果我这里只返回了最优分割点,如果需要返回其他的比如GINI值,可以自行添加。

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

split_list 参数是用来保存返回的切分点,每次切分后返回的切分点存入该list

在这里判断切分点分割的左子树和右子树是否满足“内部节点再划分所需的最小样本数>=总样本量的10%”的条件,如果满足则进行递归调用。

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

最后整合以下来个函数调用,返回一个分割点list。

可以使用sklearn库的决策树测试一下单变量分类对结果进行验证,在分类方法相同,剪枝条件一致的情况下结果是一致的。

以上这篇python实现连续变量最优分箱详解--CART算法就是小编分享给大家的全部内容了,希望能给大家一个参考,也希望大家多多支持三水点靠木。

Python 相关文章推荐
python中pass语句用法实例分析
Apr 30 Python
浅谈Python中的数据类型
May 05 Python
Python中json格式数据的编码与解码方法详解
Jul 01 Python
Python入门_浅谈字符串的分片与索引、字符串的方法
May 16 Python
SVM基本概念及Python实现代码
Dec 27 Python
Python爬虫抓取代理IP并检验可用性的实例
May 07 Python
解决Matplotlib图表不能在Pycharm中显示的问题
May 24 Python
Django框架自定义session处理操作示例
May 27 Python
如何使用python3获取当前路径及os.path.dirname的使用
Dec 13 Python
解决jupyter notebook 出现In[*]的问题
Apr 13 Python
Kmeans均值聚类算法原理以及Python如何实现
Sep 26 Python
python实现批量移动文件
Apr 05 Python
pycharm运行scrapy过程图解
Nov 22 #Python
python迭代器常见用法实例分析
Nov 22 #Python
python自动分箱,计算woe,iv的实例代码
Nov 22 #Python
python创建学生管理系统
Nov 22 #Python
Python如何计算语句执行时间
Nov 22 #Python
python生成器用法实例详解
Nov 22 #Python
关于pandas的离散化,面元划分详解
Nov 22 #Python
You might like
PHP 获取远程文件内容的函数代码
2010/03/24 PHP
AMFPHP php远程调用(RPC, Remote Procedure Call)工具 快速入门教程
2010/05/10 PHP
php常用ODBC函数集(详细)
2013/06/24 PHP
Yii控制器中操作视图js的方法
2016/07/04 PHP
php使用变量动态创建类的对象用法示例
2017/02/06 PHP
javascript 获取网页参数系统
2008/07/19 Javascript
jsp js鼠标移动到指定区域显示选项卡离开时隐藏示例
2013/06/14 Javascript
Js参数值中含有单引号或双引号问题的解决方法
2013/11/06 Javascript
jquery validate 自定义验证方法介绍 日期验证
2014/02/27 Javascript
jQuery中的jQuery()方法用法分析
2014/12/27 Javascript
JavaScript检测浏览器cookie是否已经启动的方法
2015/02/27 Javascript
JS 作用域与作用域链详解
2015/04/07 Javascript
JQuery实现鼠标移动图片显示描述层的方法
2015/06/25 Javascript
Underscore源码分析
2015/12/30 Javascript
jQuery基于toggle实现click触发DIV的显示与隐藏问题分析
2016/06/12 Javascript
jQuery EasyUI tree 使用拖拽时遇到的错误小结
2016/10/10 Javascript
js代码实现下拉菜单【推荐】
2016/12/15 Javascript
JavaScript中使用Async实现异步控制
2017/08/15 Javascript
JavaScript实现简单动态进度条效果
2018/04/06 Javascript
VUE项目中加载已保存的笔记实例方法
2019/09/14 Javascript
python高并发异步服务器核心库forkcore使用方法
2013/11/26 Python
python访问mysql数据库的实现方法(2则示例)
2016/01/06 Python
解决pyttsx3无法封装的问题
2018/12/24 Python
Python中的Socket 与 ScoketServer 通信及遇到问题解决方法
2019/04/01 Python
django框架cookie和session用法实例详解
2019/12/10 Python
Omio俄罗斯:一次搜索公共汽车、火车和飞机的机票
2018/11/17 全球购物
SOA的常见陷阱或者误解是什么
2014/10/05 面试题
毕业生个人的自我评价优秀范文
2013/10/03 职场文书
2014年卫生工作总结
2014/11/27 职场文书
学校捐书倡议书
2015/04/27 职场文书
元旦联欢晚会主持词
2015/07/01 职场文书
小学教师师德培训心得体会
2016/01/09 职场文书
幼儿园六一儿童节开幕词
2016/03/04 职场文书
Python基于Opencv识别两张相似图片
2021/04/25 Python
4种方法python批量修改替换列表中元素
2022/04/07 Python
Java 轮询锁使用时遇到问题
2022/05/11 Java/Android