鱼C论坛

 找回密码
 立即注册
查看: 1266|回复: 2

[已解决](机器学习)关于逻辑回归评分卡案例中的分箱处理过程

[复制链接]
发表于 2021-9-19 14:04:54 | 显示全部楼层 |阅读模式
20鱼币
本帖最后由 zzong2019 于 2021-9-19 14:04 编辑
  1. import numpy as np
  2. import scipy
  3. import pandas as pd
  4. import matplotlib.pyplot as plt
  5. from sklearn.linear_model import LogisticRegression as LR
  6. def graphforbestbins(DF, X, Y, m=5, n=50, graph=True):
  7.     '''
  8.     基于卡方检验进行分箱,根据最大P值选择需要合并的分箱,直到达到设置的分箱个数,并且可以绘制IV值曲线
  9.     参数设置:
  10.     DF:包含特征及标签的数据集
  11.     X:需要分箱的特征列名
  12.     Y:数据集的标签列名
  13.     m:最终想要得到的分箱个数
  14.     n:初始的分箱个数
  15.     graph:是否需要画图
  16.     '''
  17.     # 第一步,初始分箱
  18.     global bins_df
  19.     DF_1 = DF[[X, Y]].copy()  # 为了保护原数据创建一份副本
  20.     DF_1['qcut'], bins = pd.qcut(DF_1[X], q=n, retbins=True, duplicates='drop')
  21.     '''
  22.     设置retbins=True可以返回每个样本(索引值)对应的分箱
  23.     设置duplicates=True为了在出现分箱上下边界冲突时直接将分箱合并(实际分箱数可能小于设置的分箱数)
  24.     bins返回的是所有分箱上下边界组成的一维数组
  25.     '''
  26.     # 第二步,统计分箱后的样本分布情况
  27.     count_0 = DF_1.loc[DF_1[Y] == 0].groupby(by='qcut').count()[Y]  # 获取每个分箱中标签为0的样本数
  28.     count_1 = DF_1.loc[DF_1[Y] == 1].groupby(by='qcut').count()[Y]  # 获取每个分箱中标签为1的样本数
  29.     numbins = [*zip(bins, bins[1:], count_0, count_1)]  # 通过zip函数得到每个分箱的下限、上限、标签为0的样本数,标签为1的样本数组成的一个列表

  30.     # 第三步,对分箱结果进行检验,确保每个分箱中能够同时包含两种类别的标签
  31.     i = 0
  32.     n = len(numbins) - 1
  33.     while i < n:
  34.         if i != n - 1:
  35.             '''
  36.             对于num_bins从第一个分箱开始判断是否有哪一个分箱中存在标签对应的样本为0的情况,如果有就向后合并
  37.             如果执行向后合并,再校验合并后是否还存在标签对应的样本为0的情况,如果有就继续向后合并
  38.             如果没有检测到标签对应的样本为0的情况,就继续检测下一个分箱,直到倒数第二个分箱
  39.             '''
  40.             if 0 in numbins[i][2:]:
  41.                 numbins[i:i + 2] = [(
  42.                     numbins[i][0],
  43.                     numbins[i + 1][1],
  44.                     numbins[i][2] + numbins[i + 1][2],
  45.                     numbins[i][3] + numbins[i + 1][3])]
  46.             else:
  47.                 i += 1
  48.             n = len(numbins)

  49.         else:
  50.             '''
  51.             对于num_bins的最后一个分箱,如果存在标签对应的样本为0的情况,就向前合并
  52.             这样就可以确保所有的分箱都没有样本为0的情况,注意这一步结束之后break退出循环
  53.             '''
  54.             if 0 in numbins[-1][2:]:
  55.                 numbins[i - 1:i + 1] = [(
  56.                     numbins[i - 1][0],
  57.                     numbins[i][1],
  58.                     numbins[i - 1][2] + numbins[i][2],
  59.                     numbins[i - 1][3] + numbins[i][3])]
  60.             break

  61.     # 第四步,编写公式计算WOE值和IV值
  62.     def get_woe(numbins):
  63.         columns = ['min', 'max', 'count_0', 'count_1']
  64.         df = pd.DataFrame(numbins, columns=columns)
  65.         df['total'] = df['count_0'] + df['count_1']
  66.         df['percentage'] = df['total'] / df['total'].sum()
  67.         df['bad_rate'] = df['count_1'] / df['total']
  68.         df['good%'] = df['count_0'] / df['count_0'].sum()
  69.         df['bad%'] = df['count_1'] / df['count_1'].sum()
  70.         df['woe'] = np.log(df['good%'] / df['bad%'])
  71.         return df

  72.     def get_iv(df):
  73.         rate = df['good%'] - df['bad%']
  74.         iv = np.sum(rate * df['woe'])
  75.         return iv

  76.     # 第五步,利用卡方检验,对P值最大的相邻分箱进行合并,直到达到要求的最终分箱数,并绘制每次分箱合并后的IV值曲线
  77.     IV = []  # 用于存储每次分箱后计算出的iv值
  78.     axisx = []  # 用于存储每次合并后的分箱个数
  79.     while len(numbins) > n:
  80.         pvs = []  # 用于存储相邻分箱的卡方检验P值
  81.         for i in range(len(numbins) - 1):
  82.             x1 = numbins[i][2:]
  83.             x2 = numbins[i + 1][2:]
  84.             pv = scipy.stats.chi2_contingency([x1, x2])[1]
  85.             pvs.append(pv)
  86.         print(pvs)
  87.         j = pvs.index(max(pvs))  # 求出pvs列表中p值最大的元素对应的索引(准备对这个索引对应的相邻分箱执行合并)
  88.         numbins[i:i + 2] = [(numbins[j][0],
  89.                              numbins[j + 1][1],
  90.                              numbins[j][2] + numbins[j + 1][2],
  91.                              numbins[j][3] + numbins[j + 1][3]
  92.                              )]
  93.         axisx.append(len(numbins))
  94.         bins_df = get_woe(numbins)
  95.         IV.append(get_iv(bins_df))
  96.     # 第六步,根据需要绘制不同分箱个数的IV值曲线
  97.     if graph:
  98.         plt.figure(figsize=[20, 5])
  99.         plt.plot(axisx, IV, color='red')
  100.         plt.xticks(axisx)
  101.         plt.yticks(IV)
  102.         plt.xlabel('num_of_bins')
  103.         plt.ylabel('IV_value')
  104.         plt.show()
  105.     return bins_df, IV

  106. model_data=pd.read_csv(r'E:\BaiduNetdiskDownload\【机器学习】菜菜的sklearn课堂(1-12全课) (1)\05逻辑回归与评分卡\银行信贷客户数据\model_data.csv',index_col=0)
  107. graphforbestbins(model_data, 'age', 'SeriousDlqin2yrs', m=8, n=50, graph=True)
复制代码


上面是对数据集的指定某一个特征进行分箱的过程,根据卡方检验计算出P值,之后选择需要合并的分箱,直到达到设置的分箱个数,并且可以绘制IV值曲线
上面的每一个代码块我都是可以成功运行的,但是可能是我Python基础不扎实,在进行函数嵌套的时候写的有问题,整体运行下来报错:NameError: name 'bins_df' is not defined
还请大佬帮忙指点一下如何修改,感谢~~~
最佳答案
2021-9-19 14:04:55
84行
while len(numbins) > n:
条件不成立

model_data.rar

1.55 MB, 下载次数: 1

数据集

最佳答案

查看完整内容

84行 while len(numbins) > n: 条件不成立
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

发表于 2021-9-19 14:04:55 | 显示全部楼层    本楼为最佳答案   
84行
while len(numbins) > n:
条件不成立
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

 楼主| 发表于 2021-9-19 17:50:48 | 显示全部楼层
逃兵 发表于 2021-9-19 14:39
84行
while len(numbins) > n:
条件不成立

啊啊啊,我居然没检查出来,不过现在虽然能运行,但结果还是不对,问题可能出在IV值的计算上,你还能再帮我看看嘛?
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

小黑屋|手机版|Archiver|鱼C工作室 ( 粤ICP备18085999号-1 | 粤公网安备 44051102000585号)

GMT+8, 2024-4-27 22:24

Powered by Discuz! X3.4

© 2001-2023 Discuz! Team.

快速回复 返回顶部 返回列表