计算woe与vi值

from scipy.stats import chi2
def chi_bins(df,col,target,confidence=None,bins=20): # 设定自由度为1,卡方阈值为3.841,最大分箱数20
    total = df[target].count()  #计算总样本数
    bad = df[target].sum()   # 计算坏样本总数
    good = total - bad      # 计算好样本总数
    total_bin = df.groupby([col])[target].count()  # 计算每个箱体总样本数
    total_bin_table = pd.DataFrame({'total':total_bin}) #创建一个数据框保存结果
    bad_bin = df.groupby([col])[target].sum()  # 计算每个箱体的坏样本数
    bad_bin_table = pd.DataFrame({'bad':bad_bin})  #创建一个数据框保存结果
    regroup = pd.merge(total_bin_table,bad_bin_table,left_index=True,right_index=True,how='inner')  #组合total_bin 和 bad_bin
    regroup.reset_index(inplace=True)  
    regroup['good'] = regroup['total']-regroup['bad'] #计算每个箱体的好样本数
    regroup = regroup.drop(['total'],axis=1)  #删除total
    np_regroup = np.array(regroup)  # 将regroup转为numpy
    
    # 设定阈值
    freq_tab=pd.crosstab(df[col],df[target])
    freq=freq_tab.values
    cutoffs=freq_tab.index.values
    
    if confidence is None:
        cls_num=freq.shape[-1]
        confidence=chi2.isf(0.05,df=cls_num-1)
#     confidence = 3.84
    
    # 处理连续没有正样本和负样本的区间,进行合并,以免卡方报错
    i = 0
    while (i <= np_regroup.shape[0] - 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, 1] = np_regroup[i, 1] + np_regroup[i + 1, 1]  # 正样本
            np_regroup[i, 2] = np_regroup[i, 2] + np_regroup[i + 1, 2]  # 负样本
            np_regroup[i, 0] = np_regroup[i + 1, 0]
            np_regroup = np.delete(np_regroup, i + 1, 0)
            i = i - 1
        i = i + 1
    
    # 对相邻两个区间的值进行卡方计算
    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)

    # 将卡方值最小的两个区间进行合并          
    while(1):  #除非设置break,否则会一直循环下去
        if(len(chi_table)<=(bins-1) or min(chi_table)>=confidence):
            break  # 当chi_table的值个数小于等于(箱体数-1) 或 最小的卡方值大于等于卡方阈值时,循环停止
            
        chi_min_index = np.where(chi_table == min(chi_table))[0] # 找出卡方最小值的索引
        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,axis=0)
        
        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)  #删除替换前的卡方值
        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) #删除替换前的卡方值

        
# 将结果保存为一个数据框
    result_data = pd.DataFrame()
    result_data['col'] = [col]*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['bin'] = list_temp
    result_data['bad'] = np_regroup[:,1]
    result_data['good'] = np_regroup[:,2]
    result_data['bad_rate'] = result_data['bad']/total  #计算每个箱体坏样本所占总样本比例
    result_data['badattr'] = result_data['bad']/bad     #计算每个箱体坏样本所占坏样本总数的比例
    result_data['goodattr'] = result_data['good']/good  #计算每个箱体好样本所占好样本总数的比例
    result_data['woe'] = np.log(result_data['goodattr']/result_data['badattr'])  #计算每个箱体的woe值
    iv = ((result_data['goodattr']-result_data['badattr'])*result_data['woe']).sum()  #计算每个变量的iv值
    return iv

来源:

https://zhuanlan.zhihu.com/p/38440477

 

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
WOE编码和IV是一种常用的特征工程方法,它们可以用于衡量一个特征与目标变量之间的关联程度和预测能力。下面是Python计算IVWOE编码的示例代码: ```python import pandas as pd import numpy as np def calc_woe_iv(df, col, target): """ 计算指定特征的WOE编码和IV :param df: 数据集 :param col: 特征列名 :param target: 目标变量列名 :return: WOE编码和IV """ # 计算该特征每个取的数量和占比 freq = pd.DataFrame({'total': df.groupby(col)[target].count(), 'bad': df.groupby(col)[target].sum()}) freq['good'] = freq['total'] - freq['bad'] freq['bad_rate'] = freq['bad'] / freq['bad'].sum() freq['good_rate'] = freq['good'] / freq['good'].sum() # 防止出现除0错误 freq.loc[freq['bad_rate'] == 0, 'bad_rate'] = 0.0001 freq.loc[freq['good_rate'] == 0, 'good_rate'] = 0.0001 # 计算WOE编码 freq['woe'] = np.log(freq['good_rate'] / freq['bad_rate']) # 计算IV freq['iv'] = (freq['good_rate'] - freq['bad_rate']) * freq['woe'] iv = freq['iv'].sum() return freq[['woe', 'iv']].reset_index().rename(columns={col: 'value'}), iv ``` 这个函数的输入参数包括数据集`df`、特征列名`col`和目标变量列名`target`,输出WOE编码和IV。在函数中,我们首先计算了该特征每个取的数量、坏样本数量、好样本数量、坏样本率、好样本率和WOE,然后根据IV的公式计算了每个取对应的IV,并将它们相加得到总的IV。最后,我们将WOE编码和IV合并成一个DataFrame并返回。 需要注意的是,代码中为了避免出现除0错误,我们在计算WOE编码和IV时对分母加上了一个极小0.0001。同时,WOE编码和IV计算方式可以根据具体的业务需求进行调整。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值