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查询mysql中文乱码问题
Nov 09 Python
python编程开发之类型转换convert实例分析
Nov 13 Python
详解Golang 与python中的字符串反转
Jul 21 Python
TensorFlow实现iris数据集线性回归
Sep 07 Python
解决python 文本过滤和清理问题
Aug 28 Python
python字典的值可以修改吗
Jun 29 Python
Python中logging日志记录到文件及自动分割的操作代码
Aug 05 Python
python中逻辑与或(and、or)和按位与或异或(&amp;、|、^)区别
Aug 05 Python
实现Python3数组旋转的3种算法实例
Sep 16 Python
Python环境配置实现pip加速过程解析
Nov 27 Python
Python就将所有的英文单词首字母变成大写
Feb 12 Python
python疲劳驾驶困倦低头检测功能的实现
Apr 04 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
FirePHP 推荐一款PHP调试工具
2011/04/23 PHP
php上传文件并存储到mysql数据库的方法
2015/03/16 PHP
php基础设计模式大全(注册树模式、工厂模式、单列模式)
2015/08/31 PHP
使用Composer安装Yii框架的方法
2016/03/15 PHP
Thinkphp页面跳转设置跳转等待时间的操作
2019/10/16 PHP
JQuery扩展插件Validate 5添加自定义验证方法
2011/09/05 Javascript
js捕获鼠标右键菜单中的粘帖事件实现代码
2013/04/01 Javascript
js闭包实例汇总
2014/11/09 Javascript
js实现iPhone界面风格的单选框和复选框按钮实例
2015/08/18 Javascript
JS获取当前脚本文件的绝对路径
2016/03/02 Javascript
JS返回只包含数字类型的数组实例分析
2016/12/16 Javascript
two.js之实现动画效果示例
2017/11/06 Javascript
微信小程序实践之动态控制组件的显示/隐藏功能
2018/07/18 Javascript
微信小程序 MinUI组件库系列之badge徽章组件示例
2018/08/20 Javascript
Vue中keep-alive 实现后退不刷新并保持滚动位置
2020/03/17 Javascript
JS变量提升原理与用法实例浅析
2020/05/22 Javascript
基于javascript canvas实现五子棋游戏
2020/07/08 Javascript
[13:18]《一刀刀一天》之DOTA全时刻21:详解TI新赛制 A队再露獠牙
2014/06/24 DOTA
[49:41]NB vs NAVI Supermajor小组赛A组 BO3 第一场 6.2
2018/06/03 DOTA
[43:18]NB vs Infamous 2019国际邀请赛淘汰赛 败者组 BO3 第一场 8.22
2019/09/05 DOTA
[07:09]DOTA2-DPC中国联赛 正赛 Ehome vs Elephant 选手采访
2021/03/11 DOTA
python使用正则表达式提取网页URL的方法
2015/05/26 Python
python 生成器协程运算实例
2017/09/04 Python
Python实现识别手写数字 简易图片存储管理系统
2018/01/29 Python
python读取ini配置文件过程示范
2019/12/23 Python
pyqt5 QlistView列表显示的实现示例
2020/03/24 Python
canvas与html5实现视频截图功能示例
2016/12/15 HTML / CSS
爱游人:Travelliker
2017/09/05 全球购物
英国当代时尚和街头服饰店:18montrose
2018/12/15 全球购物
通息工程毕业生自荐信
2013/10/16 职场文书
单位成立周年感言
2014/01/26 职场文书
学生会个人自荐书范文
2014/02/12 职场文书
爱岗敬业演讲稿
2014/05/05 职场文书
专项法律服务方案
2014/06/11 职场文书
公共场所禁烟倡议书
2014/08/30 职场文书
《黄道婆》教学反思
2016/02/22 职场文书