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

解决的问题:

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实现二分类的卡方分箱示例就是小编分享给大家的全部内容了,希望能给大家一个参考

您可能感兴趣的文章:

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/269633.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

[linux命令技巧] mkdir -p

mkdir {dirname} 只能建立单个目录。mkdir的-p选项允许你一次性创建多层次的目录&#xff0c;而不是一次只创建单独的目录。例如&#xff0c;我们要在当前目录创建目录/home/a/b (/home为空)&#xff0c;使用命令cd /home mkdir a cd a mkdir b 当然可以&#xff0c;但是使用 m…

Git文件四种状态

git status可以看到文件是untracked 未跟踪状态 git add . 把文件添加到暂存区 接着 git status可以看到是staged状态 git commit -m "备注"

java中io流是类吗_Java中的IO流

今天刚刚看完java的io流操作&#xff0c;把主要的脉络看了一遍&#xff0c;不能保证以后使用时都能得心应手&#xff0c;但是最起码用到时知道有这么一个功能可以实现&#xff0c;下面对学习进行一下简单的总结&#xff1a;IO流主要用于硬板、内存、键盘等处理设备上得数据操作…

动态规划(冬令营课堂笔记)

简单问题 01背包 012背包 部分背包 机器分配 烽火传递 花店橱窗问题 简单问题 01背包 一个容量为m的背包&#xff0c;有n个物品&#xff0c;第i个物品的体积为wi&#xff0c;价值为ci。选择若干物品&#xff0c;使得体积总和不超过m的情况下价值总和最大。 n<100&#xff0c…

java的小区车辆管理系统_基于Java的小区车辆信息管理系统的设计与实现

软件设计开发 ComputerKnowledgeand Technology 电脑知识 第13卷第2期 (2017年1月) 基于Java的小区车辆信息管理系统的设计与实现 陈小虎&#xff0c;邓惠俊 (万博科技职业学院 计算机科学技术系&#xff0c;安徽 合肥230031) 摘要&#xff1a;世界经济与技术的发展、生活水平的…

Git使用命令行回退版本git reset --hard

git log--oneline --oneline 标记的作用是把每一个提交信息压缩为一行。默认情况下只会展示提交 ID与提交信息的首行。git log --oneline的结果如下 方法一&#xff1a; git reset --hard~回退几个版本 git reset --hard~3 表示回退三个版本&#xff0c;即从8309203回到93b1…

java 测试工具 oracle_几种测试工具的简单介绍

负载测试(LoadTest)&#xff1a;负载测试是一种性能测试&#xff0c;指数据在超负荷环境中运行&#xff0c;程序是否能够承担。 二、WinRunnerWinRunner是一种企业级的功能测试工具&#xff0c;用于检验企业应用程序是否能如期进行&#xff0c;是几款最好的测试工具之一&#x…

【玩转Eclipse】——eclipse实现代码块折叠-类似于VS中的#region……#endregion

【玩转Eclipse】——eclipse实现代码块折叠-类似于VS中的#region……#endregion http://www.cnblogs.com/Micheal-G/articles/5073778.html 转载于:https://www.cnblogs.com/Jeremy2001/p/6708679.html

Git分支命令学习使用

git branch 查看分支&#xff0c;如下图 黄色的有*号的表示当前分支 git branch 分支名 表示创建一个新分支 git checkout 分支名 表示切换到这个分支 git checkout -b 分支名 表示创建这个新分支并且切换到这个分支上

java ioexception异常_12. Java IO: 异常处理

想要查看此教程的目录请点击&#xff1a;Java IO教程目录贴地址Streams或Readers/Writers在使用过程中需要是可关闭的。这需要调用close()方法。这需要一点儿思考&#xff0c;看下面的代码&#xff1a;InputStream input new FileInputStream("c:\\data\\input-text.txt&…

NYOJ--927--dfs--The partial sum problem

/*Name: NYOJ--927--The partial sum problemAuthor: shen_渊 Date: 15/04/17 19:41Description: DFS,和 NYOJ--1058--dfs--部分和问题 基本一致&#xff0c;递归的i1注意了&#xff0c;其他没什么 */#include<cstring> #include<iostream> using namespace std; …

php 中如何重载父类的方法_PHP中子类重载父类的方法【parent::方法名】

在PHP中不能定义重名的函数&#xff0c;也包括不能再同一个类中定义重名的方法&#xff0c;所以也就没有方法重载。单在子类中可以定义和父类重名的方法&#xff0c;因为父类的方法已经在子类中存在&#xff0c;这样在子类中就可以把从父类中继承过来的方法重写。子类中重载父类…

HTML5新特性-自定义属性(data-set)

设么是data-set 在HTML5中我们可以使用data-前缀设置我们需要的自定义属性&#xff0c;来进行一些数据的存放 使用data-set可以获取这些数据 实例 <div id2 data-food皮皮虾></div> <script type"text/javascript">var len document.getElementBy…

php提交表单处理,PHP表单处理

我们可以在PHP中创建和使用表单。要获取表单数据&#xff0c;需要使用PHP超级元组&#xff1a;$_GET和$_POST。表单请求可以是get或post。 要从get请求中检索数据&#xff0c;需要使用$_GET&#xff0c;而$_POST用于检索post请求中的数据。PHP GET表单GET请求是表单的默认请求。…

git中--soft和--mixed和--hard区别

想cvbnm&#xff0c;。、、、、、

Python爬虫1-----------placekitten 入门

常用的urllib库有三个类&#xff1a;request&#xff0c;parse&#xff0c;error&#xff0c;request主要完成对url的请求&#xff0c;如proxy&#xff0c;opener&#xff0c;urlopen&#xff0c;parse主要完成对html的解析&#xff0c;error负责异常处理。 1 import urllib.re…

php标签调用,phpcms栏目标签调用代码大全

phpcms栏目标签调用代码大全$CATEGORY[$catid][catid] 栏目id$CATEGORY[$catid][module] 栏目所在的模块$CATEGORY[$catid][type] 栏目类型$CATEGORY[$catid][modelid] 栏目所属模型id$CATEGORY[$catid][catname] 栏目名称$CATEGORY[$catid][style] 栏目名称样式$CATEGORY[$cat…

怎样在mac系统里将文件拷贝到移动硬盘教程

一&#xff1a;下载这个mounty软件 地址https://mounty.app/ 下载安装 打开后菜单栏显示一座山&#xff0c;如下 接着就可以移动了

前端开发规范文档(html,css,js)

首先吐槽一句,本来想上传word文档的,可是发现博客不能上传word文档,这就很尴尬了。 首先声明该规范不是本人写的,网上搜前端规范发现这个很详细就先复制下来做笔记,当然不可能啥都按规范来,每个公司的规范都不一样..仅供参考 前端开发规范文档 Html规范 1 代码风格 1.1 缩进 **…