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引用DLL文件的方法
May 11 Python
Python2.x版本中maketrans()方法的使用介绍
May 19 Python
Python音频操作工具PyAudio上手教程详解
Jun 26 Python
python实现两张图片拼接为一张图片并保存
Jul 16 Python
python pyinstaller打包exe报错的解决方法
Nov 02 Python
wxPython实现整点报时
Nov 18 Python
Python求正态分布曲线下面积实例
Nov 20 Python
python使用pygame实现笑脸乒乓球弹珠球游戏
Nov 25 Python
tensorflow实现训练变量checkpoint的保存与读取
Feb 10 Python
使用SimpleITK读取和保存NIfTI/DICOM文件实例
Jul 01 Python
浅谈python 类方法/静态方法
Sep 18 Python
python模拟浏览器 使用selenium进入好友QQ空间并留言
Apr 12 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遍历二维数组的代码
2011/04/22 PHP
PHP获取中国时间(上海时区时间)及美国时间的方法
2017/02/23 PHP
PHP使用xpath解析XML的方法详解
2017/05/20 PHP
对textarea框的代码调试,而且功能上使用非常方便,酷
2006/06/30 Javascript
Js setInterval与setTimeout(定时执行与循环执行)的代码(可以传入参数)
2010/06/11 Javascript
js获得鼠标的坐标值的方法
2013/03/13 Javascript
JQuery设置文本框和密码框得到焦点时的样式
2013/08/30 Javascript
jquery获取radio值实例
2014/10/16 Javascript
JS+DIV+CSS排版布局实现美观的选项卡效果
2015/10/10 Javascript
JS基于VML技术实现的五角星礼花效果代码
2015/10/26 Javascript
Javascript使用uploadify来实现多文件上传
2016/11/16 Javascript
基于js文件加载优化(详解)
2018/01/03 Javascript
Node.js 路由的实现方法
2019/06/05 Javascript
使用Vue开发自己的Chrome扩展程序过程详解
2019/06/21 Javascript
layui实现数据表格table分页功能(ajax异步)
2019/07/27 Javascript
JS控制下拉列表左右选择实例代码
2020/05/08 Javascript
JS组件库AlloyTouch实现图片轮播过程解析
2020/05/29 Javascript
解决vue项目获取dom元素宽高总是不准确问题
2020/07/29 Javascript
Js数组扁平化实现方法代码总汇
2020/11/11 Javascript
[48:48]VGJ.T vs Liquid 2018国际邀请赛小组赛BO2 第二场 8.19
2018/08/21 DOTA
[40:31]Secret vs Alliacne 2019国际邀请赛小组赛 BO2 第二场 8.15
2019/08/17 DOTA
[46:12]完美世界DOTA2联赛循环赛 DM vs Matador BO2第一场 11.04
2020/11/04 DOTA
python编码总结(编码类型、格式、转码)
2016/07/01 Python
Python编程实现两个文件夹里文件的对比功能示例【包含内容的对比】
2017/06/20 Python
python文件选择对话框的操作方法
2019/06/27 Python
python tkinter组件使用详解
2019/09/16 Python
找Python安装目录,设置环境路径以及在命令行运行python脚本实例
2020/03/09 Python
Keras搭建自编码器操作
2020/07/03 Python
法国发饰品牌:Alexandre De Paris
2018/12/04 全球购物
生物化工专业个人自荐信
2013/09/26 职场文书
绿色小区申报材料
2014/08/22 职场文书
优秀大学生事迹材料
2014/12/24 职场文书
同学聚会祝酒词
2015/08/10 职场文书
新学期家长寄语2016
2015/12/03 职场文书
中学生打架检讨书之500字
2019/08/06 职场文书
HTML+css盒子模型案例(圆,半圆等)“border-radius” 简单易上手
2021/05/10 HTML / CSS