前言:鸽了两个月,重庆这两个月履历了天翻地覆的变化,后续12月自己就又羊了。现现在才好一些,小伙伴们要珍重身材,大脑苏醒很重要(ˉ﹃ˉ)。 这是关于数据预处置的第3篇文章,主讲关于woe的二三事,并附上前两期的传送门。 可以转载,请把原文链接附上,求求了~做原创文章不轻易,┗( T﹏T )┛ 在第一篇文章《万字长文详解:机械进修数据清洗与预处置(一)》末端处,我们提到了处置缺失值的还有一种比力常用方式,即利用WOE 编码。 在我过往的项目经历中线性模子利用WOE 编码的情况会多一些,特别是触及到建造评分卡的几近都利用WOE 编码。所以透彻的了解WOE 编码非常有需要。 一、什么是WOE 编码WOE (weight of evidence):证据权重。它是数据预处置的有用手段之一,但WOE 的利用处景是有限制的,只能用于监视进修,二分类使命。 它的感化有以下3点:
名词同一说明:
1.1WOE的计较公式:WOE_{i}=ln(\frac{good_{i}/good_{total}}{bad_{i}/bad_{total}}) ,其中 i 代表第 i 箱。 观察上式, good_{i}/good_{total} 代表第 i 箱正例占整体正例的百分比; 这里说明,WOE的公式份子分母是可以相互换位置的,即:好/坏比可以;坏/好照旧可以。引入ln函数是为了将括号中比率的部分做一个平滑变化处置(由于WOE的值可以很大,也能够很小)。也正是由于引入了ln,使得WOE的值域变成了 (-\infty,+\infty) 。 ln函数图像 在引入了ln函数后,观察图像会发现在大的值,也会陡峭的上升。这实在是一种傅里叶变更思绪。 固然还有个重要的点是对数函数的特征: ln(a\cdot b)=ln(a) +ln(b) , 而且 a\cdot b 的单调性不会改变。 1.2特别批改公式假如碰到分箱中,某一箱客户好or坏客户为0的情况,请用下方批改计较公式: WOE_{i}=ln(\frac{\frac{good_{i}+\lambda}{good_{total}}}{\frac{bad_{i}+\lambda}{bad_{total}}}) ,其中 \lambda 是可以更换的,该取值>0,倡议1之内。 加上 \lambda ,相当于在随机变量各组取值的频数上赋予了一个正数,这类方式称为 拉普拉斯平滑( Laplace smoothing )。 假如不用批改公式,则会出现没法计较WOE值的情况: WOE_{i}=ln(\frac{good_{i}/good_{total}}{bad_{i}/bad_{total}})=ln(\frac{good_{i} \times bad_{total}}{good_{total}\times bad_{i}}) 假如 good_{i} 为0,则份子为0, ln(0) 是没成心义的。python中会间接显现inf; 1.3WOE的一些了解,以及需留意点WOE的本质,实在是每个分箱中,这一箱好客户和坏客户的比值,也就是差别。假如WOE的绝对值越大,说明这箱的黑白客户差别也就越大;越小越差别也越小。而woe绝对值越趋近于0,表白客户黑白比越接近,由于 WOE=ln(1)=0 。固然,WOE的值的巨细也与你分箱的情况有着亲近的关系。 请牢记,WOE的绝对值越大,越说明该分组黑白客户的差别越大。而不是 坏客户的比率越大。 有很多文章说WOE必须连结单调性,我持保存态度。很多现实的营业场景WOE是显现U型的,大概有一定波动的显现U型,固然假如能连结单调最好,不能连结也无妨。 假如为了单调性去合并分箱,很有能够会致使分箱的样天职布不均;大概为了单调性使得分箱的样本数目不公道。 我们看两个例子便可以大白。 网上文章的讲授图,凡是是理想情况:随着箱数的增加,该箱坏客户比率在削减。是以WOE值是单调增加的。 图1:完全理想条件下的散布 可现实的场景、项目凡是不是这样的。下图这类U型散布才是最有能够碰到的情况。 图2:现实项目碰到的 是以碰到这类时辰,WOE的值也是可以用的。但碰到这类情况,请尽能够的把分箱数目增加一些,比如4箱变8箱,这样WOE的会变的陡峭一些。 总结一下: WOE 可以了解为当前组中正负样本的比值,与一切样本中正负样本比值的差别。这个差别是用这两个比值的比值,再取对数来暗示的。 二、WOE优点详解上方我们提到,WOE有以下益处:
2.1处置缺失值在数据中,对于为空的变量,在分箱进程中可零丁设备NUll一箱。 NULL此箱的WOE代表为空组队整体的分类的进献,权衡波动性时不计入。 null零丁为一箱 操纵null零丁为一箱,奇妙的将缺失的变量映照为WOE值,而且权衡了缺失值这一组对于整体变量的进献水平。与算法添补大概间接fillna的思绪分歧。不管是算法,大概是fillna,实在都是操纵样本去估量值,终极供模子进修。而添补的值倘使有公允,就轻易致使模子学歪了。 固然WOE纷歧定就优于算法大概最简单的fillna,缺失值处置一定是一个权衡和取舍的进程,没有a方式绝对好过b方式这么一说。很有能够,你今年用了WOE添补,过了一年多后,新的数据大量补充,这时辰算法添补缺失值便能够优于WOE添补。 2.2处置数据噪声一些持续型的变量会有一些离群点出现,这些离群点常常是数据获得大概是传输映照的时辰出现了题目。倘使有较多的数据噪声,练习模子时又不能做删除处置,一样可以零丁分箱,用WOE编码停止映照。 (90,+∞)可作为异常值组 如上图,将(90,+∞)这一组作为异常值组,即没有将异常的样本删除,一样模子也进修到了异常样本中该变量所包括的信息。 但请留意:异常值需要判定下能否需要剔除,不是放到同一箱就高枕无忧。比如年龄跨越100岁还来存款,这从现真相况是不太能够的,是以这条数据的实在性就有待商议。 三、WOE与IV值的渊源IV值,(Information Value):与WOE亲近相关的一个目标,实在就是在WOE的根本上斟酌到了分箱样本量不均匀会影响的题目。 不外IV值的限制点不异,必须是有监视使命可计较,而且必须是二分类使命。 IV值感化:用来挑选一些重要的,可以加入数据模子的变量用来暗示特征对方针猜测的进献水平,即特征的猜测才能,⼀般来说,IV值越高,该特征的猜测能才能越强,信息进献水平越高。
现实项目中,若果你发现某个目标的IV值出格高,倡议间接利用法则来分别。 3.1IV值的计较公式IV=\sum_{i=1}^{n}{(\frac{good_{i}}{good_{t}}-\frac{bad_{i}}{bad_{t}})}\ast WOE_{i} ,其中 i 为第几分箱。 我们可以从上式看到,IV值是将该变量一切分箱的iv相加,最初的和才是该变量的IV值。IV一定是>0的,而且从WOE聚焦于分箱分组的水平,转换成了对于一个变量,以及变量与变量之间相互比力的条理。 为什么说IV值一定是>0的? 当 {(\frac{good_{i}}{good_{t}}-\frac{bad_{i}}{bad_{t}})}<0时: \Rightarrow \frac{good_{i}}{good_{t}}<\frac{bad_{i}}{bad_{t}} ,好客户占整体好样本的比率是小于坏客户的,两者比率是小于1的。 \Rightarrow ln(1)=0, 所以当括号中<1时,WOE_{i}=ln(\frac{good_{i}/good_{total}}{bad_{i}/bad_{total}})<0 观察IV值计较公式,负负为正,是以IV值>0;同理可证 {(\frac{good_{i}}{good_{t}}-\frac{bad_{i}}{bad_{t}})}>0 。 当 {(\frac{good_{i}}{good_{t}}-\frac{bad_{i}}{bad_{t}})}=0 时,IV值为0。 IV值是看单个变量正负样天职布的差别,这类差别越大表白这个变量对于正负样本的区分度越高. 四、从贝叶斯的角度了解了解,WOE为什么被叫做证据权重4.1刘未鹏博主文章启发在求是汪以的文章中看到了很多关于从贝叶斯角度论述WOE。但说真话我没看懂。 后来我看到了这篇刘未鹏博主的文章给了我很多启发,思考一番后给出我自己的答案。我会尽能够的把操纵贝叶斯方式思绪变更为WOE方式的细节论述清楚。 先附上这篇文章的链接: 贝叶斯公式: P(A|B)=P(A)\bullet\frac{P(B|A)}{P(B)} 要求在B事务,已经发生条件下,A发生的几率。即后验几率 我们用贝叶斯思绪求解时最优模子时,想获得的一定是最大的后验几率,也就是最大的 P(A|B) 。 由于 P(B)=P(B|A)\bullet P(A) +P(B|\tilde{A})\bullet P(\tilde{A}) ,就是 调剂因子的分母 全几率的值是牢固的,则: P(A|B)∝P(A)\bullet P(B|A) ,也就是说后验几率的巨细 反比例于 P(A)\bullet P(B|A) ,这俩的乘积越大,后延几率也就越大。 在引入刘未鹏博主文章的这段话,以及上方固然还有个重要的点是对数函数的特征: ln(a\cdot b)=ln(a)+ln(b) ,可以方便我们停止变化 ↓ 贝叶斯模子比力理论与信息论有一个风趣的关联: 4.2贝叶斯派vs统计学派WOE的设立,是想要找到一个杰出的把持续型的变量离散化的映照方式。离散化想到了,借用树模子的思绪,把持续型的变量分箱即可。 那该怎样映照呢?每一箱里面最重要的黑白客户信息该怎样操纵? 首先我可以统计:
黑白客户比率能反应这一箱集合的客户在这个变量上的特征,刺耳点的话 能集合在一路都是一路货品。 而在计较率时,统计学派 和 贝叶斯派是这样从各自的角度动身的: 坏客户率:
好客户率:
几率( Odds ):
几率 Odds 我们在里面套一个 ln ,这样可陡峭数值,而且由于 ln 对数的运算法例,乘法可以变成加法,这样即方便求导,单调性不会遭到影响也不会改变极值的位置。 \Rightarrow ln(Odds)=ln(\frac{bad_{total}}{good_{total}}) \Rightarrow ln(\frac{P(Y=bad|X)}{P(Y=good|X)})=ln(\frac{P(X|Y=bad)}{P(X|Y=good)})+ln(\frac{P(Y=bad)}{P(Y=good)}) 这里在援用下这段话: P(h | D) ∝ P(h) * P(D | h) 翻译翻译,就是: 已知整体黑白比的情况下(先验几率已知) + 调剂因子(WOE) = 后验几率(分箱后的黑白比)。 回到4.2小节开首题目:分箱完成了,我该怎样映照才能有同一的代价标准权衡比对,给出分歧分箱对于模子的进献巨细? 那就是操纵贝叶斯方式思绪,在整体先验几率已知的情况下,黑白比( Odds )即WOE越大,对于整体先验几率的批改也就越大,对于模子整体的进献权重也就分歧。这也正是证据权重一词的由来。 换言之,同一个变量的分歧分箱,都有一个各个分箱不异的根本分数(先验几率不异),由于分歧的分箱要按照箱内各自的黑白客户比也是可以计较出来的,相减即可获得WOE值。 五、工程实现(python)代码终极要实现放入一个变量,会自动天生WOE以及IV值列表。 第一个细节:变量要停止分箱,分箱的公道性决议了WOE值计较的公道性。 这里先容我最常用的3种分箱方式:
烦琐一句,假如你要将WOE为根本建立评分卡,只管每一个变量连结6箱以上。这样建造的评分卡才能够显现均匀的正态散布,而不是很多客户挤在一坨。 4.1建立分歧分箱函数库新建一个 woe_function_library.py,用于寄存我们分歧的分箱方式。 界说了woe_calculate,该类包括以下两种函数:
挪用函数,终极会返回一个WOE以及IV值的分箱计较列表。 #!/usr/bin/env python# coding: utf-8 # In[1]: from sklearn.tree import DecisionTreeClassifier import pandas as pd import numpy as np import matplotlib.pyplot as plt from pandas.plotting import table import math # In[2]: class woe_calculate(object): def __init__(self, data, savefile): self.savefile = savefile self.data = data self.df_target0 = data[data['target'] == 0] self.df_target1 = data[data['target'] == 1] # 界说决议树最优分箱 def optimal_iv_dt(self, factorname='', box_num=6, min_lf_rate=0.1): ''' 操纵决议树获得最优分箱的鸿沟值列表\n 计较IV值 ''' data_focul = self.data[(self.data['target'] == 0) | (self.data['target'] == 1)].fillna(-999) x = data_focul[factorname].values y = data_focul['target'].values clf = DecisionTreeClassifier(criterion='gini', max_leaf_nodes=box_num, min_samples_leaf=min_lf_rate) 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 boundary = [] # 待return的分箱鸿沟值列表 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.00001 # +0.1是为了斟酌后续groupby操纵时,能包括特征最大值的样本 boundary = [min_x] + boundary + [max_x] Tree_df = data_focul.loc[:, [factorname, 'target']] Tree_df.columns = ['x', 'y'] Bin_name = 'Point_Bins' Tree_df[Bin_name] = pd.cut(x=x, bins=boundary, right=False) Tree_df_grouped = Tree_df.groupby(Bin_name)['y'] IV_result = Tree_df_grouped.agg([('Good_guy', lambda y: (y == 0).sum()), ('Bad_guy', lambda y: (y == 1).sum()), ('Total', 'count') ]) IV_result['Good_Pct'] = IV_result['Good_guy'] / IV_result['Good_guy'].sum() # 好客户占比 IV_result['Bad_Pct'] = IV_result['Bad_guy'] / IV_result['Bad_guy'].sum() # 坏客户占比 IV_result['Total_Pct'] = IV_result['Total'] / IV_result['Total'].sum() # 总客户占比 IV_result['Bad_Rate'] = IV_result['Bad_guy'] / IV_result['Total'] # 坏比率 IV_result['WOE'] = np.log(IV_result['Good_Pct'] / IV_result['Bad_Pct']) # 计较WOE IV_result['IV'] = (IV_result['Good_Pct'] - IV_result['Bad_Pct']) * IV_result['WOE'] # 计较IV # 自动标注IV最大列 IV_result['iv值最大箱'] = '_' max_index = np.argmax(IV_result['IV']) IV_result.iloc[max_index, IV_result.shape[1] - 1] = '√' IV_result = IV_result.reset_index() # 插入目标称号 IV_result.insert(0, 'Factor_name', factorname) # 天生合计行 IV_num = IV_result['IV'].sum() IV_result.loc[IV_result.shape[0]] = '' # 特定添补单元格 IV_result.iloc[IV_result.shape[0] - 1, 0] = '合计' IV_result.iloc[IV_result.shape[0] - 1, IV_result.shape[1] - 2] = IV_num # 经过IV值判定目标区分度 degree_of_target_distinction = np.select([(IV_num < 0.02), (np.logical_and(IV_num >= 0.02, IV_num < 0.1)), (np.logical_and(IV_num >= 0.1, IV_num < 0.3)), (np.logical_and(IV_num >= 0.3, IV_num < 0.5)), (IV_num >= 0.5)], ['无区分度', '弱区分度', '中区分度', '高区分度', '极高区分度']) IV_result.iloc[IV_result.shape[0] - 1, IV_result.shape[1] - 1] = degree_of_target_distinction IV_result.to_excel(self.savefile + '\\' + 'IV_dt_' + factorname + '.xlsx') print(f'变量【{factorname}】 IV值为:{IV_num}') return IV_result # 等频/等深分箱 def optimal_iv_qcut(self, factorname='', group_num=6): ''' 等频分箱\n 计较IV值 ''' data_focul = self.data[(self.data['target'] == 0) | (self.data['target'] == 1)].fillna(-999) x = data_focul[factorname].values y = data_focul['target'].values df_select = data_focul.loc[:, [factorname, 'target']] df_select.columns = ['x', 'y'] Bin_name = 'Point_Bins' df_select[Bin_name] = pd.qcut(x=x, q=group_num, duplicates='drop') Tree_df_grouped = df_select.groupby(Bin_name)['y'] IV_result = Tree_df_grouped.agg([('Good_guy', lambda y: (y == 0).sum()), ('Bad_guy', lambda y: (y == 1).sum()), ('Total', 'count') ]) IV_result['Good_Pct'] = IV_result['Good_guy'] / IV_result['Good_guy'].sum() # 好客户占比 IV_result['Bad_Pct'] = IV_result['Bad_guy'] / IV_result['Bad_guy'].sum() # 坏客户占比 IV_result['Total_Pct'] = IV_result['Total'] / IV_result['Total'].sum() # 总客户占比 IV_result['Bad_Rate'] = IV_result['Bad_guy'] / IV_result['Total'] # 坏比率 IV_result['WOE'] = np.log(IV_result['Good_Pct'] / IV_result['Bad_Pct']) # 计较WOE IV_result['IV'] = (IV_result['Good_Pct'] - IV_result['Bad_Pct']) * IV_result['WOE'] # 计较IV # 自动标注IV最大列 IV_result['iv值最大箱'] = '_' max_index = np.argmax(IV_result['IV']) IV_result.iloc[max_index, IV_result.shape[1] - 1] = '√' IV_result = IV_result.reset_index() # 插入目标称号 IV_result.insert(0, 'Factor_name', factorname) # 天生合计行 IV_num = IV_result['IV'].sum() IV_result.loc[IV_result.shape[0]] = '' # 特定添补单元格 IV_result.iloc[IV_result.shape[0] - 1, 0] = '合计' IV_result.iloc[IV_result.shape[0] - 1, IV_result.shape[1] - 2] = IV_num # 经过IV值判定目标区分度 degree_of_target_distinction = np.select([(IV_num < 0.02), (np.logical_and(IV_num >= 0.02, IV_num < 0.1)), (np.logical_and(IV_num >= 0.1, IV_num < 0.3)), (np.logical_and(IV_num >= 0.3, IV_num < 0.5)), (IV_num >= 0.5)], ['无区分度', '弱区分度', '中区分度', '高区分度', '极高区分度']) IV_result.iloc[IV_result.shape[0] - 1, IV_result.shape[1] - 1] = degree_of_target_distinction IV_result.to_excel(self.savefile + '\\' + 'IV_qcut_' + factorname + '.xlsx') print(f'变量【{factorname}】 IV值为:{IV_num}') return IV_result 在返回的函数列表中,我优化了下展现的结果,否则看几百个变量眼睛会受不了:
就像这样: 做了一点点细小的工作.jpg 4.2编写测算IV的主进程代码函数库封装好了,那挪用数据我们测试下: test_health.csv 还是老的数据。 # -*- coding: utf-8 -*-""" Created on 2022.12.29 @author: zmjh 代码应像诗一样优美 """ import pandas as pd import numpy as np df_all = pd.read_csv(r'C:\Users\Desktop\archive\test_health.csv').fillna(0) df_all # 实例化函数 cp = cus_portrai(data=df_all,savefile=r'C:\Users\Desktop\result') # 挪用决议树最优分箱,测算WOE及IV值 df_iv_baseline_value = cp.optimal_iv_dt('light_decelerations',min_lf_rate =0.05) df_iv_baseline_value 成果以下: 上方为决议树最优分箱法,下方我们则利用等频分箱 df_iv_qcut_baseline_value = cp.optimal_iv_qcut('histogram_median',group_num=6)df_iv_qcut_baseline_value 两个变量的IV值都比力高,而WOE则显现了讲授部分提到的U型散布,究其缘由是由于:坏客户率并不会随着样本增加而下降,反之亦然。 U型散布需要连系营业现实意义判定,并不是U型散布就是不公道的。 参考 [1]《风控模子—WOE与IV目标的深入了解利用》——求是汪在路上 [2]《WOE编码与IV值 》 参考
|
导读:我们把关于信息处理的理论称为信息论,它是20世纪40年代从通信实践中发展并总结
整理了网上的公开数据集,分类下载如下,希望节约大家的时间。1.经济金融1.1.宏观经济
做数据可视化或者数据分析的朋友可能经常会碰到的问题就是有想法没有数据。想到我有几
我们常常会遇到数据不足的情况。比如,你遇到的一个任务,目前只有小几百的数据,然而
在这个用数据说话的时代,能够打动人的往往是用数据说话的理性分析,无论是对于混迹职
如果有两名篮球手A和B,本来,无论是两分球还是三分球,A都要比B投得准,但是一个赛季
1.什么是数据库呢?每个人家里都会有冰箱,冰箱是用来干什么的?冰箱是用来存放食物的
数据源:NUMBEO自从我的“randy77:数据看中国vs世界:2020年世界各国人均GDP最新排名
编辑导语:数据分析是让很多职场人头疼的一个话题,一张简简单单的图片上有几条曲线,
本篇文章主要为我们介绍了大数据的概念、发展以及相关应用。“Big Data is like teena
编辑导语:作为一名数据小白,在日常学习和工作中经常会接触到数据。随着用户数据与业
8月16日,国家统计局发布了2022年7月70个大中城市商品住宅销售价格变动情况。数据显示
本文来源:时代周报 作者:阿力米热人口是国家发展的基础性、全局性、长期性和战略性
中新网7月23日电 (中新财经 吴涛)23日,在第五届数字中国建设峰会期间举行的大数据分
来源:环球时报【环球时报综合报道】受疫情影响,今年上半年访韩外国游客数量持续猛减
日前,国家统计局公布了中国一季度的实际GDP增长率,结果2022年1季度中国GDP实际增长
原文链接:知乎专栏目录:一、为什么要做一份数据报告二、制作数据报告的流程一、为什
文 | 李童 孟令稀编辑 | 陈臣自9月30日首度回应“双标”争议以来,海天味业市值已下跌
编辑导语:无论是产品还是运营,数据分析都是其日常工作中不可忽略的一个板块,那么数
数据分析在如今的求职场上越来越重要。然而,让很多朋友困惑的是,我是没有编程基础的
声明:本站内容由网友分享或转载自互联网公开发布的内容,如有侵权请反馈到邮箱 1415941@qq.com,我们会在3个工作日内删除,加急删除请添加站长微信:15314649589
Copyright @ 2022-2044 杭州共生网络 www.gongshengyun.cn Powered by Discuz!