(机器学习)关于逻辑回归评分卡案例中的分箱处理过程(无法实现对多个特征进行分箱)

  统计/机器学习 Python    浏览次数:175        分享
0

下面是对数据集的指定某一个特征进行分箱的过程,根据卡方检验计算出P值,之后选择需要合并的分箱,直到达到设置的分箱个数,并且可以绘制IV值曲线,我现在已经能实现对'age'这个特征进行分箱,但是之后我再想把所有的特征进行分箱的时候发现所有特征的分箱结果都是和age这个特征一样的,我怀疑是自己写函数嵌套出现了问题,还请各位大佬指教~


import numpy as np
import scipy
import pandas as pd
import matplotlib.pyplot as plt
from sklearn.linear_model import LogisticRegression as LR

def graphforbestbins(DF, X, Y, m=5, n=50, graph=True):
    '''
    基于卡方检验进行分箱,根据最大P值选择需要合并的分箱,直到达到设置的分箱个数,并且可以绘制IV值曲线
    参数设置:
    DF:包含特征及标签的数据集
    X:需要分箱的特征列名
    Y:数据集的标签列名
    m:最终想要得到的分箱个数
    n:初始的分箱个数
    graph:是否需要画图
    '''
    # 第一步,初始分箱
    DF_1 = DF[[X, Y]].copy()  # 为了保护原数据创建一份副本
    DF_1['qcut'], bins = pd.qcut(DF_1[X], q=n, retbins=True, duplicates='drop')
    '''
    设置retbins=True可以返回每个样本(索引值)对应的分箱
    设置duplicates=True为了在出现分箱上下边界冲突时直接将分箱合并(实际分箱数可能小于设置的分箱数)
    bins返回的是所有分箱上下边界组成的一维数组
    '''
    # 第二步,统计分箱后的样本分布情况
    count_0 = DF_1.loc[DF_1[Y] == 0].groupby(by='qcut').count()[Y]  # 获取每个分箱中标签为0的样本数
    count_1 = DF_1.loc[DF_1[Y] == 1].groupby(by='qcut').count()[Y]  # 获取每个分箱中标签为1的样本数
    numbins = [*zip(bins, bins[1:], count_0, count_1)]  # 通过zip函数得到每个分箱的下限、上限、标签为0的样本数,标签为1的样本数组成的一个列表

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

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

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

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

    # 第五步,利用卡方检验,对P值最大的相邻分箱进行合并,直到达到要求的最终分箱数,并绘制每次分箱合并后的IV值曲线
    def get_bins(numbins, m):
        IV = []  # 用于存储每次分箱后计算出的iv值
        axisx = []  # 用于存储每次合并后的分箱个数
        while len(numbins) > m:
            pvs = []  # 用于存储相邻分箱的卡方检验P值
            for i in range(len(numbins) - 1):
                x1 = numbins[i][2:]
                x2 = numbins[i + 1][2:]
                pv = scipy.stats.chi2_contingency([x1, x2])[1]
                pvs.append(pv)
            j = pvs.index(max(pvs))  # 求出pvs列表中p值最大的元素对应的索引(准备对这个索引对应的相邻分箱执行合并)
            numbins[j:j + 2] = [(numbins[j][0],
                                 numbins[j + 1][1],
                                 numbins[j][2] + numbins[j + 1][2],
                                 numbins[j][3] + numbins[j + 1][3]
                                 )]
            axisx.append(len(numbins))
            bins_df = get_woe(numbins)
            IV.append(get_iv(bins_df))
        return axisx, IV, numbins

    # 第六步,根据需要绘制不同分箱个数的IV值曲线
    if graph:
        plt.figure(figsize=[20, 5])
        plt.plot(axisx, IV, color='red')
        plt.xticks(axisx)
        plt.xlabel('num_of_bins')
        plt.ylabel('IV_value')
        plt.show()
    return bins_df, axisx, IV
model_data=pd.read_csv(r'E:\BaiduNetdiskDownload\【机器学习】菜菜的sklearn课堂(1-12全课) (1)\05逻辑回归与评分卡\银行信贷客户数据\model_data.csv',index_col=0)
graphforbestbins(model_data, 'age', 'SeriousDlqin2yrs', m=5, n=50, graph=True)


 

zzong2020   2021-09-20 13:42



    还没有回答。我来答!  


  相关主题

python里有没有类似matlab里linspace的功能?   2回答

请问python已知某个元素,怎么得到该元素在dataframe中的位置   1回答

python里@property有什么用   2回答

怎么用python批量生成含重复数值的数列?   1回答

python怎么把字符串类json转成字典dict类型变量?   4回答

Jupiter notebook中显示一个dataframe所有的列   2回答

怎么合并(串联)两个dataframe?   1回答

python里的<<或者>>符号是什么意思?   2回答

怎么对有多个空格的字符串进行split?   2回答

print的时候报错:TypeError: unsupported operand type(s) for /: 'str' and 'int'   1回答

python里的continue是什么意思   2回答

python 时间格式问题   1回答



回答问题时需要注意什么?

我们谢绝在回答前讲“生动”的故事。

我们谢绝“这么简单,你自己想”、“书上有的,你认真看”这类的回答;如果你认为对方的提问方式或者内容不妥,你可以直接忽略该问题,不用进行任何作答,甚至可以对该问题投反对票。

我们谢绝答非所问。

我们谢绝自己不会、硬要回答。

我们感激每一个用户在编写答案时的努力与付出!