python实现二分类的卡方分箱示例


Posted in Python onNovember 22, 2019

解决的问题:

1、实现了二分类的卡方分箱;

2、实现了最大分组限定停止条件,和最小阈值限定停止条件;

问题,还不太清楚,后续补充。

1、自由度k,如何来确定,卡方阈值的自由度为 分箱数-1,显著性水平可以取10%,5%或1%

算法扩展:

1、卡方分箱除了用阈值来做约束条件,还可以进一步的加入分箱数约束,以及最小箱占比,坏人率约束等。

2、需要实现更多分类的卡方分箱算法;

具体代码如下:

# -*- coding: utf-8 -*-
"""
Created on Wed Nov 28 16:54:58 2018
@author: wolfly_fu
解决的问题:
1、实现了二分类的卡方分箱
2、实现了最大分组限定停止条件,和最小阈值限定停止条件;
问题,
1、自由度k,如何来确定?
算法扩展:
1、卡方分箱除了用阈值来做约束条件,还可以进一步的加入分箱数约束,以及最小箱占比,坏人率约束等。
2、需要实现更多分类的卡方分箱算法
"""
 
import pandas as pd
import numpy as np
from scipy.stats import chi2
 
#导入数据
df = pd.read_csv(u'test.csv')
 
#计算卡方统计量
def cal_chi2(input_df, var_name, Y_name): ##二分类,,计算每个变量值的卡方统计量
  '''
  df = input_df[[var_name, Y_name]]
  var_values = sorted(list(set(df[var_name])))
  Y_values = sorted(list(set(df[Y_name])))
  #用循环的方式填充
  chi2_result = pd.DataFrame(index=var_values, columns=Y_values)  
  for var_value in var_values:
    for Y_value in Y_values:
      chi2_result.loc[var_value][Y_value] = \
      df[(df[var_name]==var_value)&(df[Y_name]==Y_value)][var_name].count()
  '''
  input_df = input_df[[var_name, Y_name]]  #取数据
  all_cnt = input_df[Y_name].count() #样本总数
  all_0_cnt = input_df[input_df[Y_name] == 0].shape[0] # 二分类的样本数量
  all_1_cnt = input_df[input_df[Y_name] == 1].shape[0]
  expect_0_ratio = all_0_cnt * 1.0 / all_cnt #样本分类比例
  expect_1_ratio = all_1_cnt * 1.0 / all_cnt 
  
  #对变量的每个值计算实际个数,期望个数,卡方统计量 
  var_values = sorted(list(set(input_df[var_name])))
  actual_0_cnt = []    # actual_0 该值,类别为0的数量
  actual_1_cnt = []    # actual_1 该值,类别为1的数量
  actual_all_cnt = []
  expect_0_cnt = []    # expect_0 类别0 的卡方值
  expect_1_cnt = []    # expect_1 类别1 的卡方值 
  chi2_value = []     # chi2_value 该组的卡方值
  
  for value in var_values:
    actual_0 = input_df[(input_df[var_name]==value)&(input_df[Y_name]==0)].shape[0] #该值,类别为0的数量
    actual_1 = input_df[(input_df[var_name]==value)&(input_df[Y_name]==1)].shape[0]
    actual_all = actual_0 + actual_1 #总数
    expect_0 = actual_all * expect_0_ratio #类别0 的 期望频率
    expect_1 = actual_all * expect_1_ratio
    
    chi2_0 = (expect_0 - actual_0)**2 / expect_0 #类别0 的卡方值
    chi2_1 = (expect_1 - actual_1)**2 / expect_1
    
    actual_0_cnt.append(actual_0) #样本为0的,该值的数量
    actual_1_cnt.append(actual_1)
    
    actual_all_cnt.append(actual_all) #改组的总样本数
    expect_0_cnt.append(expect_0) #类别0 的 期望频率
    expect_1_cnt.append(expect_1)
    
    chi2_value.append(chi2_0 + chi2_1) #改变量值的卡方值
    
  chi2_result = pd.DataFrame({'actual_0':actual_0_cnt, 'actual_1':actual_1_cnt, 'expect_0':expect_0_cnt, \
                'expect_1':expect_1_cnt, 'chi2_value':chi2_value, var_name+'_start':var_values, \
                var_name+'_end':var_values}, \
                columns=[var_name+'_start', var_name+'_end', 'actual_0', 'actual_1', 'expect_0', 'expect_1', 'chi2_value'])
  
  return chi2_result, var_name 
 
#定义合并区间的方法
def merge_area(chi2_result, var_name, idx, merge_idx):
  #按照idx和merge_idx执行合并
  chi2_result.ix[idx, 'actual_0'] = chi2_result.ix[idx, 'actual_0'] + chi2_result.ix[merge_idx, 'actual_0']
  chi2_result.ix[idx, 'actual_1'] = chi2_result.ix[idx, 'actual_1'] + chi2_result.ix[merge_idx, 'actual_1']
  chi2_result.ix[idx, 'expect_0'] = chi2_result.ix[idx, 'expect_0'] + chi2_result.ix[merge_idx, 'expect_0']  
  chi2_result.ix[idx, 'expect_1'] = chi2_result.ix[idx, 'expect_1'] + chi2_result.ix[merge_idx, 'expect_1']  
  chi2_0 = (chi2_result.ix[idx, 'expect_0'] - chi2_result.ix[idx, 'actual_0'])**2 / chi2_result.ix[idx, 'expect_0']
  chi2_1 = (chi2_result.ix[idx, 'expect_1'] - chi2_result.ix[idx, 'actual_1'])**2 / chi2_result.ix[idx, 'expect_1']
 
  chi2_result.ix[idx, 'chi2_value'] = chi2_0 + chi2_1   #计算卡方值
  
  #调整每个区间的起始值
  if idx < merge_idx:
    chi2_result.ix[idx, var_name+'_end'] = chi2_result.ix[merge_idx, var_name+'_end'] #向后扩大范围
  else:
    chi2_result.ix[idx, var_name+'_start'] = chi2_result.ix[merge_idx, var_name+'_start'] ##,向前扩大范围
    
  chi2_result = chi2_result.drop([merge_idx]) #删掉行
  chi2_result = chi2_result.reset_index(drop=True)
  
  return chi2_result
 
#自动进行分箱,使用最大区间限制
def chiMerge_maxInterval(chi2_result, var_name, max_interval=5): #最大分箱数 为 5 
  groups = chi2_result.shape[0] #各组的卡方值,数量
  while groups > max_interval:
    min_idx = chi2_result[chi2_result['chi2_value']==chi2_result['chi2_value'].min()].index.tolist()[0] #寻找最小的卡方值
    if min_idx == 0:
      chi2_result = merge_area(chi2_result, var_name, min_idx, min_idx+1) #合并1和2组
    elif min_idx == groups-1:  
      chi2_result = merge_area(chi2_result, var_name, min_idx, min_idx-1)
      
    else: #寻找左右两边更小的卡方组
      if chi2_result.loc[min_idx-1, 'chi2_value'] > chi2_result.loc[min_idx+1, 'chi2_value']:
        chi2_result = merge_area(chi2_result, var_name, min_idx, min_idx+1)
      else:
        chi2_result = merge_area(chi2_result, var_name, min_idx, min_idx-1)
    groups = chi2_result.shape[0]
 
  return chi2_result
 
 
def chiMerge_minChiSquare(chi2_result, var_name): #(chi_result, maxInterval=5):
  '''
  卡方分箱合并--卡方阈值法,,同时限制,最大组为6组,,可以去掉
  '''
  threshold = get_chiSquare_distribution(4, 0.1)
  min_chiSquare = chi2_result['chi2_value'].min()
  #min_chiSquare = chi_result['chi_square'].min()
  group_cnt = len(chi2_result)
  # 如果变量区间的最小卡方值小于阈值,则继续合并直到最小值大于等于阈值
  while(min_chiSquare < threshold and group_cnt > 6):
    min_idx = chi2_result[chi2_result['chi2_value']==chi2_result['chi2_value'].min()].index.tolist()[0] #寻找最小的卡方值
    #min_index = chi_result[chi_result['chi_square']==chi_result['chi_square'].min()].index.tolist()[0]
    # 如果分箱区间在最前,则向下合并
    if min_idx == 0:
      chi2_result = merge_area(chi2_result, var_name, min_idx, min_idx+1) #合并1和2组
    elif min_idx == group_cnt -1:  
      chi2_result = merge_area(chi2_result, var_name, min_idx, min_idx-1)
      
    else: #寻找左右两边更小的卡方组
      if chi2_result.loc[min_idx-1, 'chi2_value'] > chi2_result.loc[min_idx+1, 'chi2_value']:
        chi2_result = merge_area(chi2_result, var_name, min_idx, min_idx+1)
      else:
        chi2_result = merge_area(chi2_result, var_name, min_idx, min_idx-1)
        
    min_chiSquare = chi2_result['chi2_value'].min()
    group_cnt = len(chi2_result)
 
  return chi2_result
 
#分箱主体部分包括两种分箱方法的主体函数,其中merge_chiSquare()是对区间进行合并,
#get_chiSquare_distribution()是根据自由度和置信度得到卡方阈值。我在这里设置的是自由度为4
#,置信度为10%。两个自定义函数如下
 
def get_chiSquare_distribution(dfree=4, cf=0.1):
  '''
  根据自由度和置信度得到卡方分布和阈值
  dfree:自由度k= (行数-1)*(列数-1),默认为4   #问题,自由度k,如何来确定?
  cf:显著性水平,默认10%
  '''
  percents = [ 0.95, 0.90, 0.5,0.1, 0.05, 0.025, 0.01, 0.005]
  df = pd.DataFrame(np.array([chi2.isf(percents, df=i) for i in range(1, 30)]))
  df.columns = percents
  df.index = df.index+1
  # 显示小数点后面数字
  pd.set_option('precision', 3)
  return df.loc[dfree, cf]

以上这篇python实现二分类的卡方分箱示例就是小编分享给大家的全部内容了,希望能给大家一个参考,也希望大家多多支持三水点靠木。

Python 相关文章推荐
Python urllib模块urlopen()与urlretrieve()详解
Nov 01 Python
使用Python开发windows GUI程序入门实例
Oct 23 Python
在Python的Flask框架中实现单元测试的教程
Apr 20 Python
玩转python selenium鼠标键盘操作(ActionChains)
Apr 12 Python
itchat接口使用示例
Oct 23 Python
Python根据已知邻接矩阵绘制无向图操作示例
Jun 23 Python
Python中 map()函数的用法详解
Jul 10 Python
Pycharm设置去除显示的波浪线方法
Oct 28 Python
pyqt 实现QlineEdit 输入密码显示成圆点的方法
Jun 24 Python
python基于pdfminer库提取pdf文字代码实例
Aug 15 Python
Keras 中Leaky ReLU等高级激活函数的用法
Jul 05 Python
python数字图像处理:图像简单滤波
Jun 28 Python
python的等深分箱实例
Nov 22 #Python
基于python实现学生信息管理系统
Nov 22 #Python
基于python cut和qcut的用法及区别详解
Nov 22 #Python
python创建学生成绩管理系统
Nov 22 #Python
Python计算不规则图形面积算法实现解析
Nov 22 #Python
python实现连续变量最优分箱详解--CART算法
Nov 22 #Python
pycharm运行scrapy过程图解
Nov 22 #Python
You might like
php简单静态页生成过程
2008/03/27 PHP
PHP编实现程动态图像的创建代码
2008/09/28 PHP
PHP 文章中的远程图片采集到本地的代码
2009/07/30 PHP
PHP多线程抓取网页实现代码
2010/07/22 PHP
深入for,while,foreach遍历时间比较的详解
2013/06/08 PHP
ThinkPHP模板标签eq if 中区分0,null,false的方法
2017/03/24 PHP
laravel 修改记住我功能的cookie保存时间的方法
2019/10/14 PHP
Javascript UrlDecode函数代码
2010/01/09 Javascript
Javascript学习笔记5 类和对象
2010/01/11 Javascript
Js setInterval与setTimeout(定时执行与循环执行)的代码(可以传入参数)
2010/06/11 Javascript
jQuery中阻止冒泡事件的方法介绍
2014/04/12 Javascript
js的toUpperCase方法用法实例
2015/01/27 Javascript
a标签跳转到指定div,jquery添加和移除class属性的实现方法
2016/10/10 Javascript
vue 粒子特效的示例代码
2017/09/19 Javascript
nodejs用gulp管理前端文件方法
2018/06/24 NodeJs
vue-cli的工程模板与构建工具详解
2018/09/27 Javascript
利用JavaScript将Excel转换为JSON示例代码
2019/06/14 Javascript
解决Vue router-link绑定事件不生效的问题
2020/07/22 Javascript
[34:47]完美世界DOTA2联赛PWL S2 Magma vs LBZS 第一场 11.18
2020/11/18 DOTA
Python编程中的文件读写及相关的文件对象方法讲解
2016/01/19 Python
Python安装官方whl包和tar.gz包的方法(推荐)
2017/06/04 Python
python os.path.isfile 的使用误区详解
2019/11/29 Python
Python os模块常用方法和属性总结
2020/02/20 Python
使用python创建生成动态链接库dll的方法
2020/05/09 Python
Pyinstaller加密打包应用的示例代码
2020/06/11 Python
利用python制作拼图小游戏的全过程
2020/12/04 Python
Python新建项目自动添加介绍和utf-8编码的方法
2020/12/26 Python
L’urv官网:精品女性运动服品牌
2019/07/07 全球购物
英国老牌潮鞋店:Offspring
2019/08/19 全球购物
材料成型专业个人求职信范文
2013/09/25 职场文书
汽车工程专业应届生求职信
2013/10/19 职场文书
技能比武方案
2014/05/21 职场文书
关爱残疾人演讲稿
2014/05/24 职场文书
大学生自我评价200字(4篇)
2014/09/17 职场文书
golang 实现对Map进行键值自定义排序
2021/04/28 Golang
Android开发EditText禁止输入监听及InputFilter字符过滤
2022/06/10 Java/Android