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,说明数据采集得不错。这些信息虽然简单,但能帮你快速判断变量质量。

我的小技巧: 对于连续变量,我习惯同时看均值和分位数(25%、50%、75%)。如果均值远大于中位数,说明数据右偏,可能有极端大值。这时候就要考虑做截尾处理或者对数变换了。

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

看到了吗?收入越低,坏账率越高。这个趋势非常清晰,说明「收入」是个好变量。如果某个变量分箱后坏账率忽高忽低、没有单调性,那就要小心了——可能是个噪音变量。

我曾经踩过的坑: 有一次我遇到一个变量,分箱后坏账率呈现「U型」——两头高中间低。我当时没多想就把它放进模型了,结果模型上线后效果很差。后来才发现,这个变量其实和另一个变量高度相关,导致多重共线性。所以,双变量分析不仅要看单调性,还要结合业务逻辑判断。

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),说明好客户多。这个趋势和业务直觉完全吻合。

核心要点: IV值不是越高越好。我见过有人把IV做到0.8以上,结果模型上线后一塌糊涂。为什么?因为IV过高往往意味着变量和目标之间存在「过度拟合」的关系,或者变量本身包含了未来信息(比如用「是否已经逾期」来预测逾期,这属于数据泄露)。所以,IV在0.1到0.5之间是比较理想的区间。

4.4 本章知识体系

为了让你更直观地理解这三者的关系,我画了一张流程图:

探索性分析知识体系 单变量分析 缺失率 / 分布 / 异常值 双变量分析 坏账率趋势 / 单调性 IV与WOE计算 量化区分能力 输出结果 ✅ 变量质量报告(缺失率、异常值、分布形态) ✅ 变量与目标的关系(坏账率趋势、单调性检验) ✅ IV值排序(筛选强变量,剔除弱变量) ✅ WOE编码(为后续逻辑回归做准备)

你看,这三个步骤是层层递进的。单变量分析帮你筛掉「脏数据」,双变量分析帮你找到「有趋势的变量」,IV与WOE帮你「量化排序」。每一步都有它的价值,缺一不可。

我的建议: 在实际项目中,我通常会把所有变量的IV值排个序,然后挑出IV大于0.02的变量进入下一步。但注意,IV只是参考,不是唯一标准。有些变量IV不高,但业务上非常重要(比如「是否在法院失信名单」),这种也要保留。说白了,模型是工具,业务判断才是灵魂。

好,这一章就到这里。记住,探索性分析不是走过场,而是帮你建立对数据的「体感」。你花的时间越多,后面建模就越顺。


专注资料整理