python最优分箱计算iv值_基于sklearn决策树的最优分箱与IV值计算-Python实现

一、问题描述:

在实际建模问题中,衍生加工许多特征变量之后,一般而言,首先需要对衍生变量的预测能力做一个快速、初步的评估。针对二分类问题,如信贷风险模型的好坏客户预测与评分,我们一般用IV值(Information Value)来衡量特征变量的预测能力,然后再筛选出IV值高于某个阈值的一篮子特征来进行下一步的建模工作。

为了计算某个变量的IV,首先需要对其进行分箱。如果强制变量分箱的WOE单调性,这样可能就会低估某些非线性变量的IV值,如U型变量。因此,为了尽可能使得IV值计算最大,同时尽可能保证分箱的单调性(让预测变量对目标变量有更好的解释性),我们利用决策树的信息增益最大化思想来实现变量的最优分箱。

注:本文主要讨论最优分箱与IV值计算的实现过程,对EDA分析、异常值处理等方面不做详细探讨。

二、实现思路:利用sklearn决策树,DecisionTreeClassifier的.tree_属性获得决策树的节点划分值;

基于上述得到的划分值,利用pandas.cut函数对变量进行分箱;

计算各个分箱的WOE、IV值。

三、数据说明:

测试数据是kaggle案例的训练数据 - Give Me Some Credit;Give Me Some Credit​www.kaggle.com

该案例数据总共有150000条样本,11个变量,其中1个目标变量,10个特征变量;

其中,目标变量为SeriousDlqin2yrs:表示未来是否为逾期90天+,1表示逾期90天+,即通常意义上的坏客户,0则表示没有逾期90天+的好客户。

四、代码部分:

0. import相关模块:

from sklearn.tree import DecisionTreeClassifier

import pandas as pd

import numpy as np读入数据:

data = pd.read_csv('cs-training.csv')

print(data.shape)

data.head()部分数据展示

2. 获得最优分箱边界值函数的实现:

def optimal_binning_boundary(x: pd.Series, y: pd.Series, nan: float = -999.) -> list:

'''利用决策树获得最优分箱的边界值列表'''

boundary = [] # 待return的分箱边界值列表

x = x.fillna(nan).values # 填充缺失值

y = y.values

clf = DecisionTreeClassifier(criterion='entropy', #“信息熵”最小化准则划分

max_leaf_nodes=6, # 最大叶子节点数

min_samples_leaf=0.05) # 叶子节点样本数量最小占比

clf.fit(x.reshape(-1, 1), y) # 训练决策树

n_nodes = clf.tree_.node_count

children_left = clf.tree_.children_left

children_right = clf.tree_.children_right

threshold = clf.tree_.threshold

for i in range(n_nodes):

if children_left[i] != children_right[i]: # 获得决策树节点上的划分边界值

boundary.append(threshold[i])

boundary.sort()

min_x = x.min()

max_x = x.max() + 0.1 # +0.1是为了考虑后续groupby操作时,能包含特征最大值的样本

boundary = [min_x] + boundary + [max_x]

return boundary

测试optimal_binning_boundary函数:

optimal_binning_boundary(x=data['RevolvingUtilizationOfUnsecuredLines'],

y=data['SeriousDlqin2yrs'])

输出:

[0.0,

0.11458224803209305,

0.21776090562343597,

0.49497613310813904,

0.6981423199176788,

0.8596274554729462,

50708.1]

3. 获得某个变量各个分箱的WOE、IV值函数的实现:

def feature_woe_iv(x: pd.Series, y: pd.Series, nan: float = -999.) -> pd.DataFrame:

'''计算变量各个分箱的WOE、IV值,返回一个DataFrame'''

x = x.fillna(nan)

boundary = optimal_binning_boundary(x, y, nan) # 获得最优分箱边界值列表

df = pd.concat([x, y], axis=1) # 合并x、y为一个DataFrame,方便后续计算

df.columns = ['x', 'y'] # 特征变量、目标变量字段的重命名

df['bins'] = pd.cut(x=x, bins=boundary, right=False) # 获得每个x值所在的分箱区间

grouped = df.groupby('bins')['y'] # 统计各分箱区间的好、坏、总客户数量

result_df = grouped.agg([('good', lambda y: (y == 0).sum()),

('bad', lambda y: (y == 1).sum()),

('total', 'count')])

result_df['good_pct'] = result_df['good'] / result_df['good'].sum() # 好客户占比

result_df['bad_pct'] = result_df['bad'] / result_df['bad'].sum() # 坏客户占比

result_df['total_pct'] = result_df['total'] / result_df['total'].sum() # 总客户占比

result_df['bad_rate'] = result_df['bad'] / result_df['total'] # 坏比率

result_df['woe'] = np.log(result_df['good_pct'] / result_df['bad_pct']) # WOE

result_df['iv'] = (result_df['good_pct'] - result_df['bad_pct']) * result_df['woe'] # IV

print(f"该变量IV = {result_df['iv'].sum()}")

return result_df

测试feature_woe_iv函数:

feature_woe_iv(x=data['RevolvingUtilizationOfUnsecuredLines'],

y=data['SeriousDlqin2yrs'])

输出:

上述结果可以复制到Excel中做数据条上色处理,提升可视化效果:

如上图所示,变量RevolvingUtilizationOfUnsecuredLines,分箱WOE趋势单调,bad_rate风险排序性较好,IV值>1.0则说明该变量预测能力很强。

你可能感兴趣的:(python最优分箱计算iv值)