IV
- 概念:
- IV的全称是Information Value,中文意思是信息价值,或者信息量。
- 作用:
- 构建分类模型时,对特征进行筛选,挑选特征时 用来衡量自变量(特征)的预测能力
- ”用IV去衡量变量预测能力“的理解
- 我们假设在一个分类问题中,目标变量的类别有两类:Y1,Y2。对于一个待预测的样本A,要判断A属于Y1还是Y2,我们是需要一定的信息,假设这个信息总量是I,而这些所需要的信息,就蕴含在所有的待预测样本的特征C1,C2,C3,……,Cn中,那么,对于其中的一个特征Ci来说,其蕴含的信息越多,那么它对于判断A属于Y1还是Y2的贡献就越大,Ci的信息价值就越大,Ci的IV就越大,它就越应该进入到入模变量列表中。
-
公式:
计算整个特征的IV值 :
WOE
- WOE的全称是“Weight of Evidence”,即证据权重。WOE是对原始特征的一种编码形式。要对一个特征进行WOE编码,需要首先把这个变量进行分组处理(也叫离散化、分箱等等,说的都是一个意思)。
-
WOE的计算公式:
公式含义:
pyi是这个组中正例样本占整个样本中正例样本的比例
pni是这个组中负例样本占整个样本中负例样本的比例
(#yi是这个组中正例样本的数量 )
(#ni是这个组中负例样本的数量 )
(#yT是整个样本中所有正例样本的数量)
(#nT是整个样本中所有负例样本的数量 )
公式表示: “当前分组中正例样本占所有样本中所有正例样本的比例”和“当前分组中负例样本占所有样本中所有负例样本比例”的差异 - 公式变换:
公式表示:当前这个组中响应的客户和未响应客户的比值,和所有样本中这个比值的差异
WOE越大,这种差异越大,这个分组里的样本响应的可能性就越大(这组数据分到正例的概率越大),WOE越小,差异越小,这个分组里的样本响应的可能性就越小
分母是固定的,如果分子中的yi越大,则WOE返回的数值越大
用实例介绍IV的计算和使用
- 例子
- 假设现在某个公司举行一个活动,在举行这个活动之前,先在小范围的客户中进行了一次试点,收集了一些用户对这次活动的一些响应,然后希望通过这些数据,去构造一个模型,预测如果举行这次的活动,是否能够得到很好的响应或者得到客户的响应概率之类。
- 假设我们已经从公司客户列表中随机抽取了100000个客户进行了营销活动测试,收集了这些客户的响应结果,作为我们的建模数据集,其中响应的客户有10000个。另外假设我们也已经提取到了这些客户的一些变量,作为我们模型的候选变量集,这些变量包括以下这些:
- 最近一个月是否有购买;
- 最近一次购买金额;
- 最近一笔购买的商品类别;
- 是否是公司VIP客户;
-
假设,我们已经对这些变量进行了离散化,统计的结果如下面几张表所示
(1) 最近一个月是否有过购买:
(2) 最近一次购买金额:
(3) 最近一笔购买的商品类别:
(4) 是否是公司VIP客户:
计算WOE和IV
-
以其中的一个变量“最近一次购买金额”变量为例:
-
计算WOE
WOE的基本特点:
- 当前分组中,响应的比例越大,WOE值越大;
- 当前分组WOE的正负,由当前分组响应和未响应的比例,与样本整体响应和未响应的比例的大小关系决定,当前分组的比例小于样本整体比例时(分子小于分母),WOE为负,当前分组的比例大于整体比例时(分子大于分母),WOE为正,当前分组的比例和整体比例相等时(分子等于分母),WOE为0。
WOE描述了某一特征的当前这个分组,对判断该特征是否会响应(或者说属于哪个类)所起到影响方向和大小,当WOE为正时,特征当前取值对判断个体是否会响应起到的正向的影响,当WOE为负时,起到了负向影响。而WOE值的大小,则是这个影响的大小的体现。 -
计算IV
IV的特点:
- 对于特征的一个分组,这个分组的响应和未响应的比例与样本整体响应和未响应的比例(WOE)相差越大,IV值越大,否则,IV值越小;
- 极端情况下,当前分组的响应和未响应的比例和样本整体的响应和未响应的比例相等时,IV值为0;
-
计算变量总IV值:
IV值的比较和变量预测能力的排序
其他三个特征的iv和woe计算同上
最近一次购买金额的IV为0.49270645
最近一个月是否有过购买的IV为0.250224725
最近一笔购买的商品类别的IV为0.615275563
是否为公司VIP客户的IV为1.56550367
IV排序: 是否是公司VIP客户 > 最近一笔购买的商品类别 > 最近一次购买金额 > 最近一个月是否有过购买
“是否是公司VIP客户”是预测能力最高的特征,“最近一个月是否有过购买”是预测能力最低的特征
关于IV和WOE的进一步思考:为什么用IV而不是直接用WOE
从计算公式来看,对于特征的一个分组,IV是WOE乘以这个分组响应占比和未响应占比的差。而一个特征的IV等于各分组IV的和。WOE构造出一个和,只需要把特征各个分组的WOE和取绝对值再相加,(取绝对值是因为WOE可正可负,如果不取绝对值,则会把特征的区分度通过正负抵消的方式抵消掉):
用IV而不是直接用WOE的原因:
- 指标值不应该是负数 ,iv中乘以 (py-pn) 这个系数,保证了特征每个分组的结果都是非负数
-
主要原因: 乘以(py-pn)后,体现出了特征当前分组中个体的数量占整体个体数量的比例
从上表可以看到,特征取1时,响应比达到90%,对应的WOE很高,但对应的IV却很低,原因就在于IV在WOE的前面乘以了一个系数(py-pn),而这个系数很好的考虑了这个分组中样本占整体样本的比例,比例越低,这个分组对特征整体预测能力的贡献越低。相反,如果直接用WOE的绝对值加和,会得到一个很高的指标,这是不合理的
分箱
-
数据分箱(也称为离散分箱或分段)是一种数据预处理技术,用于减少次要观察误差的影响,是一种将多个连续值分组为较少数量的“分箱”的方法。简单说就是将连续型特征进行离散化。
关于人年龄的数据
对连续性特征进行离散化
-
注意:
- 分箱的数据不一定必须是数字,它们可以是任何类型的值,如“狗”,“猫”,“仓鼠”等。 分箱也用于图像处理,通过将相邻像素组合成单个像素,它可用于减少数据量。
-
分箱的作用&意义
- 离散特征的增加和减少都很容易,易于模型的快速迭代,提升计算速度
- 特征离散化后,模型会更稳定,比如如果对用户年龄离散化,20-30作为一个区间,不会因为一个用户年龄长了一岁就变成一个完全不同的人。
- 特征离散化以后,起到了简化了模型的作用,可以适当降低了模型过拟合的风险。
-
pandas实现数据的分箱:pd.cut()
import numpy as np import pandas as pd from pandas import Series, DataFrame score_list = np.linspace(0,20,num=11) print(score_list) #[ 0. 2. 4. 6. 8. 10. 12. 14. 16. 18. 20.] #设置分箱:方式1 bins=[0,4,8,16,20] #指定分箱数据的范围 score_cat=pd.cut(score_list,bins=bins) score_cat.value_counts() #输出结果: (0, 4] 2 (4, 8] 2 (8, 16] 4 (16, 20] 2 #设置分箱:方式2 #指定分箱数据的个数 pd.cut(score_list,bins=4).value_counts() #输出结果: (-0.02, 5.0] 3 (5.0, 10.0] 3 (10.0, 15.0] 2 (15.0, 20.0] 3 #设置分箱:方式3 #label参数的作用:设置分箱的每一个范围的标识 #指定分箱数据的个数 pd.cut(score_list,bins=4,labels=['a','b','c','d']).value_counts() #输出结果: a 3 b 3 c 2 d 3 pd.cut(score_list,bins=4,labels=range(4)).value_counts() #输出结果: 0 3 1 3 2 2 3 3
pd.qcut() ·qcut根据值的频率来选择箱子的均匀间隔,即每个箱子含有的数的数量相同
factors=np.random.randn(9)
pd.qcut(factors,3).value_counts() #计算每个分组中含有数的数量
#输出结果:
(-1.1289999999999998, -0.124] 3
(-0.124, 0.393] 3
(0.393, 1.496] 3
cut与qcut的区别:
1.cut:按连续数据的大小分到各个桶里,每个桶里样本量可能不同,但每个桶相当于等长的区间
2.qcut:每个桶的样本数量一定(等频分箱)
特征是连续性倾向于使用qcut,离散型倾向于使用cut注意:分箱后就可以求解出IV和WOE的值了。如果想对连续性特征进行离散化,需要对分箱后的每组(箱)数据进行woe或者iv编码,然后才能放进模型训练。
import sklearn.datasets as ds
bc = ds.load_breast_cancer() #加载乳腺癌数据
feature = bc.data #特征
target = bc.target #标签
feature.shape #(569, 30)
#查看第1列数据范围,判定其为连续性数据
feature[:,1].min(),feature[:,1].max()
#(9.71, 39.28)
#对其进行分箱处理,将其离散化
fea_bins = pd.cut(feature[:,1],bins=5)
fea_bins.value_counts()
#输出结果:
(9.68, 15.624] 113
(15.624, 21.538] 299
(21.538, 27.452] 129
(27.452, 33.366] 25
(33.366, 39.28] 3
#对分箱后的特征列进行woe编码 crosstab()交叉表
#每组中正例和反例样本的数量
gi = pd.crosstab(fea_bins,target)
gi
#输出结果:
col_0 0 1
row_0
(9.68, 15.624] 8 105
(15.624, 21.538] 101 198
(21.538, 27.452] 90 39
(27.452, 33.366] 11 14
(33.366, 39.28] 2 1
#样本数据中正例样本和反例样本的数量
gb = pd.Series(data=target).value_counts()
gb
#输出结果:
1 357
0 212
#规定0类别为正例样本,1为反例样本
gbi = (gi[0]/gi[1]) / (gb[0]/gb[1])
gbi
#输出结果:
row_0
(9.68, 15.624] 0.128302
(15.624, 21.538] 0.858991
(21.538, 27.452] 3.886067
(27.452, 33.366] 1.323113
(33.366, 39.28] 3.367925
#WOE的计算
woe = np.log(gbi)
woe
#输出结果:
(9.68, 15.624] -2.053369
(15.624, 21.538] -0.151997
(21.538, 27.452] 1.357398
(27.452, 33.366] 0.279987
(33.366, 39.28] 1.214297
#计算IV
iv=((gi[0]/gb[0])-(gi[1]/gb[1]))*woe
iv
#输出结果:
row_0
(9.68, 15.624] 0.526447
(15.624, 21.538] 0.011887
(21.538, 27.452] 0.427967
(27.452, 33.366] 0.003548
(33.366, 39.28] 0.008054
f_iv=iv.sum()
f_iv #0.977902238264725
#进行映射操作
dict = iv.to_dict()
dict
#输出结果:
{Interval(9.68, 15.624, closed='right'): 0.5264465134478181,
Interval(15.624, 21.538, closed='right'): 0.011887192576072856,
Interval(21.538, 27.452, closed='right'): 0.4279665436826456,
Interval(27.452, 33.366, closed='right'): 0.0035477507112311505,
Interval(33.366, 39.28, closed='right'): 0.008054237846957362}
ivs_bins = fea_bins.map(dict)
ivs_bins.tolist()