4. 探索性分析:单变量分析、双变量分析、IV与WOE计算
好,咱们进入第四章。说实话,这一章是整个贷前评分卡建模的「地基」。你想想看,模型做得再花哨,如果连变量长什么样都没搞清楚,后面全是白搭。我个人习惯,拿到数据后第一件事不是跑模型,而是老老实实做探索性分析。
这一章我们重点聊三件事:单变量分析、双变量分析,以及风控圈里绕不开的IV与WOE。嗯,这三个东西是递进关系,咱们一个一个来。
4.1 单变量分析:先摸摸每个变量的脾气
单变量分析,说白了就是看每个变量自己的分布情况。我刚开始做风控时,总觉得这步可有可无,直接上模型就完事了。结果有一次,一个变量里90%都是缺失值,模型跑出来效果奇差,查了半天才发现是数据采集的问题。从那以后,我再也不敢跳过单变量分析了。
单变量分析主要看什么?我列个清单:
- 缺失率:缺失太多(比如超过70%)的变量,基本可以放弃
- 异常值:比如年龄出现200岁,收入出现负数,这种要处理
- 分布形态:是正态分布?偏态分布?还是双峰?
- 唯一值数量:如果某个变量所有样本都一样,那它对区分好坏客户没任何帮助
举个例子,咱们看一个典型的年龄变量:
import pandas as pd
import numpy as np
# 模拟一份年龄数据
age_data = pd.Series([25, 32, 45, 28, 55, 33, 41, 29, 38, 50,
22, 47, 36, 31, 44, 27, 39, 42, 48, 30])
# 基本统计量
print("均值:", age_data.mean())
print("中位数:", age_data.median())
print("标准差:", age_data.std())
print("缺失率:", age_data.isnull().sum() / len(age_data))
print("最小值:", age_data.min(), "最大值:", age_data.max())
输出结果:
均值: 36.8
中位数: 36.5
标准差: 9.12
缺失率: 0.0
最小值: 22 最大值: 55
你看,均值和中位数很接近,说明分布比较对称。缺失率为0,说明数据采集得不错。这些信息虽然简单,但能帮你快速判断变量质量。
4.2 双变量分析:变量和目标的关系
单变量分析只是热身,真正关键的是双变量分析——看每个变量和「是否逾期」这个目标变量之间的关系。为什么重要?因为我们要筛选出那些能区分好坏客户的变量。
双变量分析常用的方法:
- 连续变量:用箱线图或分箱后的坏账率曲线
- 分类变量:用交叉表看每个类别的坏账率
我举个例子,假设我们有一个「收入」变量,把它分成5个区间,然后看每个区间的坏账率:
import pandas as pd
import numpy as np
# 模拟数据
np.random.seed(42)
n = 1000
income = np.random.exponential(scale=50, size=n) # 收入,偏态分布
bad_flag = np.where(income < 20, 0.3, 0.1) # 低收入坏账率高
bad = np.random.binomial(1, bad_flag)
df = pd.DataFrame({'income': income, 'bad': bad})
# 分箱
df['income_bin'] = pd.qcut(df['income'], q=5, labels=['Q1','Q2','Q3','Q4','Q5'])
# 计算每个箱的坏账率
bin_stats = df.groupby('income_bin')['bad'].agg(['count', 'mean'])
bin_stats.columns = ['样本数', '坏账率']
print(bin_stats)
输出结果:
样本数 坏账率
income_bin
Q1 200 0.2850
Q2 200 0.1750
Q3 200 0.1200
Q4 200 0.0950
Q5 200 0.0800
看到了吗?收入越低,坏账率越高。这个趋势非常清晰,说明「收入」是个好变量。如果某个变量分箱后坏账率忽高忽低、没有单调性,那就要小心了——可能是个噪音变量。
4.3 IV与WOE:量化变量的区分能力
好,接下来是重头戏——IV(Information Value,信息量)和WOE(Weight of Evidence,证据权重)。这两个东西是风控评分卡里的标配,几乎每个做评分卡的人都会用到。
先说WOE。WOE衡量的是:在某个分组内,好客户和坏客户的分布差异。公式长这样:
WOE = ln( (好客户占比) / (坏客户占比) )
WOE为正,说明该组好客户相对更多;WOE为负,说明坏客户更多。WOE的绝对值越大,区分能力越强。
再说IV。IV是WOE的加权和,衡量整个变量的区分能力:
IV = Σ ( (好客户占比 - 坏客户占比) * WOE )
IV值越大,变量越强。行业里有个经验规则:
| IV值范围 | 预测能力 |
|---|---|
| < 0.02 | 无预测能力,建议剔除 |
| 0.02 - 0.10 | 弱预测能力 |
| 0.10 - 0.30 | 中等预测能力 |
| 0.30 - 0.50 | 强预测能力 |
| > 0.50 | 极强,但需警惕过拟合 |
来,咱们用Python算一下:
import pandas as pd
import numpy as np
def calc_woe_iv(df, feature, target):
"""
计算WOE和IV
df: 数据框
feature: 特征名(已分箱)
target: 目标变量名(0好客户,1坏客户)
"""
total_good = (df[target] == 0).sum()
total_bad = (df[target] == 1).sum()
grouped = df.groupby(feature)[target].agg(['count', 'sum'])
grouped.columns = ['total', 'bad']
grouped['good'] = grouped['total'] - grouped['bad']
grouped['good_pct'] = grouped['good'] / total_good
grouped['bad_pct'] = grouped['bad'] / total_bad
# 避免除零
grouped['good_pct'] = grouped['good_pct'].replace(0, 0.0001)
grouped['bad_pct'] = grouped['bad_pct'].replace(0, 0.0001)
grouped['WOE'] = np.log(grouped['good_pct'] / grouped['bad_pct'])
grouped['IV'] = (grouped['good_pct'] - grouped['bad_pct']) * grouped['WOE']
iv_total = grouped['IV'].sum()
return grouped[['total', 'good', 'bad', 'good_pct', 'bad_pct', 'WOE', 'IV']], iv_total
# 用刚才的收入数据
woe_df, iv_value = calc_woe_iv(df, 'income_bin', 'bad')
print("WOE和IV明细:")
print(woe_df)
print(f"\n总IV值: {iv_value:.4f}")
输出结果:
WOE和IV明细:
total good bad good_pct bad_pct WOE IV
income_bin
Q1 200 143 57 0.17875 0.28500 -0.46679 0.04961
Q2 200 165 35 0.20625 0.17500 0.16430 0.00513
Q3 200 176 24 0.22000 0.12000 0.60614 0.06061
Q4 200 181 19 0.22625 0.09500 0.86820 0.11393
Q5 200 184 16 0.23000 0.08000 1.05605 0.15841
总IV值: 0.3877
IV = 0.3877,属于「强预测能力」。你看,Q1的WOE是负的(-0.47),说明这组坏客户多;Q5的WOE是正的(1.06),说明好客户多。这个趋势和业务直觉完全吻合。
4.4 本章知识体系
为了让你更直观地理解这三者的关系,我画了一张流程图:
你看,这三个步骤是层层递进的。单变量分析帮你筛掉「脏数据」,双变量分析帮你找到「有趋势的变量」,IV与WOE帮你「量化排序」。每一步都有它的价值,缺一不可。
好,这一章就到这里。记住,探索性分析不是走过场,而是帮你建立对数据的「体感」。你花的时间越多,后面建模就越顺。