卡方分箱代码--处理连续没有正样本或负样本的区间

1.数据源文件

链接: https://pan.baidu.com/s/1ndgWRcPoPH8DKdkQ-HCrFg
提取码: 2s3k

2.处理连续没有正样本或负样本的区间

import pandas as pd
import numpy as np

data = pd.read_csv(u'1.csv', header=0)
# 根据自由度和显著性水平,查找卡方分布表临界值,即置信度水平
# 定义一个卡方分箱(可设置参数置信度水平与箱的个数)停止条件为大于置信水平且小于bin的数目
def ChiMerge( df, variable, flag, confidenceVal,bin):
    """
    运行前需要 import pandas as pd 和 import numpy as np
    df:data传入一个数据框仅包含一个需要卡方分箱的变量与正负样本标识(正样本为1,负样本为0)
    variable:需要卡方分箱的变量名称(字符串)
    flag:正负样本标识的名称(字符串)
    confidenceVal:置信度水平(默认是不进行抽样95%)
    bin:最多箱的数目
    sample: 为抽样的数目(默认是不进行抽样),因为如果观测值过多运行会较慢
    """
    # 进行数据格式化录入
    total_num = df.groupby([variable])[flag].count()  # 统计需分箱变量每个值数目
    total_num = pd.DataFrame({'total_num': total_num})  # 创建一个数据框保存之前的结果
    positive_class = df.groupby([variable])[flag].sum()  # 统计需分箱变量每个值正样本数
    positive_class = pd.DataFrame({'positive_class': positive_class})  # 创建一个数据框保存之前的结果
    regroup = pd.merge(total_num, positive_class, left_index=True, right_index=True,
                       how='inner')  # 组合total_num与positive_class
    regroup.reset_index(inplace=True)
    regroup['negative_class'] = regroup['total_num'] - regroup['positive_class']  # 统计需分箱变量每个值负样本数
    regroup = regroup.drop('total_num', axis=1)
    np_regroup = np.array(regroup)  # 把数据框转化为numpy(提高运行效率)
    print(np_regroup)
    print('已完成数据读入,正在计算数据初处理')
    # print(np_regroup.shape)     # np_regroup 数组数据 (661,3)
    # print(np_regroup.shape[0])  # np_regroup 元素个数   661
# 处理连续没有正样本或负样本的区间,并进行区间的合并(以免卡方值计算报错)
    print(np_regroup[0, 0])  # 2
    print(np_regroup[0, 1])  # 0    positive_class值
    print(np_regroup[0, 2])  # 1    negative_class值
    print(np_regroup[1, 0])  # 3
    print(np_regroup[1, 1])  # 0    positive_class值
    print(np_regroup[1, 2])  # 1    negative_class值
    i = 0
    while i <= np_regroup.shape[0] - 2:   # i <= 661-2
        if (np_regroup[i, 1] == 0 and np_regroup[i + 1, 1] == 0) or (np_regroup[i, 2] == 0 and np_regroup[i + 1, 2] == 0):
            np_regroup[i, 0] = np_regroup[i + 1, 0]                     # 3
            np_regroup[i, 1] = np_regroup[i, 1] + np_regroup[i + 1, 1]  # 正样本0
            np_regroup[i, 2] = np_regroup[i, 2] + np_regroup[i + 1, 2]  # 负样本2
            # print(str(i) + '-->[' + str(np_regroup[i, 0]) + ','+str(np_regroup[i, 1]) + ','+str(np_regroup[i, 2])+']')
            np_regroup = np.delete(np_regroup, i + 1, 0)
            i = i - 1
        i = i + 1
    #     print('-->'+str(i))
    # print(11111111111111111111111111)
    # print(np_regroup[0, 0])
    # print(np_regroup[0, 1])
    # print(np_regroup[0, 2])
    print(np_regroup)
    print(np_regroup.shape[0])
    # 对相邻两个区间进行卡方值计算
    chi_table = np.array([])  # 创建一个数组保存相邻两个区间的卡方值
    for i in np.arange(np_regroup.shape[0] - 1):
        chi = (np_regroup[i, 1] * np_regroup[i + 1, 2] - np_regroup[i, 2] * np_regroup[i + 1, 1]) ** 2 \
          * (np_regroup[i, 1] + np_regroup[i, 2] + np_regroup[i + 1, 1] + np_regroup[i + 1, 2]) / \
          ((np_regroup[i, 1] + np_regroup[i, 2]) * (np_regroup[i + 1, 1] + np_regroup[i + 1, 2]) * (
                  np_regroup[i, 1] + np_regroup[i + 1, 1]) * (np_regroup[i, 2] + np_regroup[i + 1, 2]))
        chi_table = np.append(chi_table, chi)
    print('已完成数据初处理,正在进行卡方分箱核心操作')
    print(chi_table)

# 把卡方值最小的两个区间进行合并(卡方分箱核心)
    while min(chi_table) < confidenceVal and len(chi_table) > (bin - 1):    # 最小值小于置信度水平 and 长度大于最大箱数-1
        chi_min_index = np.argwhere(chi_table == min(chi_table))[0]  # 找出卡方值最小的位置索引
        print(chi_min_index)
        np_regroup[chi_min_index, 1] = np_regroup[chi_min_index, 1] + np_regroup[chi_min_index + 1, 1]
        np_regroup[chi_min_index, 2] = np_regroup[chi_min_index, 2] + np_regroup[chi_min_index + 1, 2]
        np_regroup[chi_min_index, 0] = np_regroup[chi_min_index + 1, 0]
        np_regroup = np.delete(np_regroup, chi_min_index + 1, 0)
        print(np_regroup)
        if chi_min_index == np_regroup.shape[0] - 1:  # 最小值是最后两个区间的时候
            # 计算合并后当前区间与前一个区间的卡方值并替换
            chi_table[chi_min_index - 1] = (np_regroup[chi_min_index - 1, 1] * np_regroup[chi_min_index, 2] - np_regroup[
            chi_min_index - 1, 2] * np_regroup[chi_min_index, 1]) ** 2 \
                                       * (np_regroup[chi_min_index - 1, 1] + np_regroup[chi_min_index - 1, 2] +
                                          np_regroup[chi_min_index, 1] + np_regroup[chi_min_index, 2]) / \
                                       ((np_regroup[chi_min_index - 1, 1] + np_regroup[chi_min_index - 1, 2]) * (
                                                   np_regroup[chi_min_index, 1] + np_regroup[chi_min_index, 2]) * (
                                                    np_regroup[chi_min_index - 1, 1] + np_regroup[chi_min_index, 1]) * (
                                                    np_regroup[chi_min_index - 1, 2] + np_regroup[chi_min_index, 2]))
            # 删除替换前的卡方值
            chi_table = np.delete(chi_table, chi_min_index, axis=0)
            print(chi_table)

        else:
            # 计算合并后当前区间与前一个区间的卡方值并替换
            chi_table[chi_min_index - 1] = (np_regroup[chi_min_index - 1, 1] * np_regroup[chi_min_index, 2] - np_regroup[
            chi_min_index - 1, 2] * np_regroup[chi_min_index, 1]) ** 2 \
                                       * (np_regroup[chi_min_index - 1, 1] + np_regroup[chi_min_index - 1, 2] +
                                          np_regroup[chi_min_index, 1] + np_regroup[chi_min_index, 2]) / \
                                       ((np_regroup[chi_min_index - 1, 1] + np_regroup[chi_min_index - 1, 2]) * (
                                                   np_regroup[chi_min_index, 1] + np_regroup[chi_min_index, 2]) * (
                                                    np_regroup[chi_min_index - 1, 1] + np_regroup[chi_min_index, 1]) * (
                                                    np_regroup[chi_min_index - 1, 2] + np_regroup[chi_min_index, 2]))
            # 计算合并后当前区间与后一个区间的卡方值并替换
            chi_table[chi_min_index] = (np_regroup[chi_min_index, 1] * np_regroup[chi_min_index + 1, 2] - np_regroup[
            chi_min_index, 2] * np_regroup[chi_min_index + 1, 1]) ** 2 \
                                   * (np_regroup[chi_min_index, 1] + np_regroup[chi_min_index, 2] + np_regroup[
            chi_min_index + 1, 1] + np_regroup[chi_min_index + 1, 2]) / \
                                   ((np_regroup[chi_min_index, 1] + np_regroup[chi_min_index, 2]) * (
                                               np_regroup[chi_min_index + 1, 1] + np_regroup[chi_min_index + 1, 2]) * (
                                                np_regroup[chi_min_index, 1] + np_regroup[chi_min_index + 1, 1]) * (
                                                np_regroup[chi_min_index, 2] + np_regroup[chi_min_index + 1, 2]))
            # 删除替换前的卡方值
            chi_table = np.delete(chi_table, chi_min_index + 1, axis=0)
            print(chi_table)
    print('已完成卡方分箱核心操作,正在保存结果')
    print("--------------------------------")
    print(np_regroup)

# 把结果保存成一个数据框
    result_data = pd.DataFrame()  # 创建一个保存结果的数据框
    result_data['variable'] = [variable] * np_regroup.shape[0]  # 结果表第一列:变量名
    list_temp = []
    for i in np.arange(np_regroup.shape[0]):
        if i == 0:
            x = '0' + ',' + str(np_regroup[i, 0])
        elif i == np_regroup.shape[0] - 1:
            x = str(np_regroup[i - 1, 0]) + '+'
        else:
            x = str(np_regroup[i - 1, 0]) + ',' + str(np_regroup[i, 0])
        list_temp.append(x)
    result_data['interval'] = list_temp  # 结果表第二列:区间,前开后闭
    result_data['flag_0'] = np_regroup[:, 2]  # 结果表第三列:负样本数目
    result_data['flag_1'] = np_regroup[:, 1]  # 结果表第四列:正样本数目

    return result_data

# 调用函数参数示例
if __name__ == '__main__':
    bins = ChiMerge(data, 'value', 'badorgood', 12.59, 6)
    total = bins['flag_0'].sum()+bins['flag_1'].sum()
    bins['bad_rate'] = bins['flag_1'] / total   # 计算每个箱体坏样本(原为1)所占总样本比例
    bins['badattr'] = (bins['flag_1'] + 1) / (bins['flag_1'].sum()+1)   # 计算每个箱体坏样本所占坏样本总数的比例 加1避免分子为0
    bins['goodattr'] = (bins['flag_0']+1) / (bins['flag_0'].sum()+1)    # 计算每个箱体好样本所占好样本总数的比例 加1避免分子为0
    print(bins)
    bins['woe'] = np.log(bins['badattr'] / bins['goodattr'])  # 计算每个箱体的woe值
    bins['iv'] = (bins['badattr'] - bins['goodattr']) * bins['woe']     # 计算每个变量的iv值
    bins.to_csv('3.csv', sep=',', header=True, index=False)
    print(bins)
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值