第2章 数据探索与可视化:EDA、分布分析、相关性分析

拿到一份信用评分建模的数据集,你会先干什么?很多新手上来就调参数、跑模型,结果往往是一顿操作猛如虎,一看效果原地杵。我个人的习惯是:先不急,沉下心来做一遍EDA。说白了,数据探索就是给你的模型打个“地基”,地基不稳,后面再怎么调参都没用。

这一章我们就聊聊信用评分场景下,EDA到底怎么做、分布分析和相关性分析能发现哪些坑。我会结合实际项目经验,把那些书上不写但实战常见的雷区给你指出来。

2.1 为什么EDA是建模的第一道滤网

EDA(探索性数据分析)不光是画几张图、算几个统计量。它真正的价值是帮你回答三个问题:

  • 数据长什么样?(类型、缺失、异常)
  • 变量之间有什么关系?(线性?非线性?共线?)
  • 数据质量够不够建模?(脏数据、样本偏差)

记得有一次我在做一个信贷申请评分卡项目,特征有40多个。直觉告诉我“工作类型”这个变量应该很有区分度,但一画分布图发现:有个类别占比不到0.5%,而且坏账率极高。如果不做EDA就直接建模,这个变量会被模型当作强信号,但实际推广时遇到这个小众群体就崩了。嗯,这就是EDA该发现的坑。

我的建议:在EDA阶段至少花整个项目周期的20%时间。信用评分模型对变量稳定性要求很高,EDA做透,后面调参才能有的放矢。

2.2 单变量分布分析:摸清每个特征的脾气

单变量分析是EDA的起点。我通常会分成两步:

  1. 描述统计量:均值、中位数、标准差、偏度、峰度、最小最大值。
  2. 可视化:直方图 + 箱线图 + 密度曲线。

信用评分里有个经典场景:收入变量。收入分布通常是右偏的(长尾巴朝右),少数高收入者把均值拉得很高。如果直接用均值填充缺失,或者不进行变换就放进逻辑回归,模型会很难看。

看一个简单的Python代码片段:

import pandas as pd
import numpy as np

# 假设 df 是训练数据,'income' 是收入特征
desc = df['income'].describe()
skew = df['income'].skew()
kurt = df['income'].kurtosis()

print("偏度:", skew, " | 峰度:", kurt)
# 如果偏度 > 1 或 < -1,通常需要做变换
分布形态 典型场景 常用处理方式
右偏(正偏) 收入、申请金额 log变换、Box-Cox、分箱
左偏(负偏) 信用评分本身(高分集中) 平方根、指数变换
双峰 年龄(年轻人+中年人峰值) 分群建模或哑变量化
我曾经踩过的坑:给一个偏度高达2.3的变量做了log变换,结果模型AUC涨了0.02,但上线后样本外不稳定。后来发现是因为变换后出现了极端小值(接近负无穷),分箱后反而引入了噪音。所以变换后一定要检查极端值,必要时截断或做Woe编码。

2.3 相关性分析:找共线、找冗余、找线索

单变量看完,就要看变量之间的关系了。信用评分模型里,最忌讳的就是强共线性。如果两个变量相关系数超过0.8,模型解释性就会打架,而且逻辑回归的系数估计会不稳定。

我一般同时算三种相关系数:

  • 皮尔逊:适合连续且大致正态分布的变量。
  • 斯皮尔曼:顺序变量或非线性单调关系。
  • 点双列:二分类目标与连续变量之间的相关性(信用评分常用)。

项目里我习惯先画一个热力图(用seaborn),一眼看出成对的相关性。然后算VIF(方差膨胀因子),把VIF > 10的变量逐一排查。

import seaborn as sns
import matplotlib.pyplot as plt
from statsmodels.stats.outliers_influence import variance_inflation_factor

# 热力图
corr = df.corr()
sns.heatmap(corr, annot=True, cmap='coolwarm')
plt.show()

# VIF计算
X = df.drop('target', axis=1)
vif_data = pd.DataFrame()
vif_data['feature'] = X.columns
vif_data['VIF'] = [variance_inflation_factor(X.values, i) for i in range(X.shape[1])]

你想想看,假如发现“月收入”和“年收入”相关系数0.98,你果断删掉一个——这不光是消除共线,更是防止模型过拟合。我在一个车贷评分项目中就遇到过“贷款金额”和“车辆价格”VIF高达15,保留两个变量反而让模型的泛化能力下降,去掉一个后AUC还微涨了0.005。

2.4 多变量探索与交叉验证

单变量和成对分析之后,还要做分层探索。比如在信用评分里,我常做“按违约标签分组”看各特征的均值差异,或者用交叉表看“职业 x 教育程度”下的违约率。这能帮你发现特征交互的线索。

举个具体案例:在某个消费贷项目中,单独看“逾期次数”对违约的区分度很高,但按“还款方式”分组后发现,自动扣款的用户逾期次数几乎不影响违约率,而手动还款的用户逾期1次违约风险就翻倍。这个交互如果不做分层探索,建模时就会错失信息。

一个实用技巧:我每次EDA都会做一张“变量重要性速查表”——包含缺失率、唯一值数、均值、方差、与目标的相关性、VIF、偏度。这样后续特征筛选时一目了然,也方便跟业务方对齐。

下面这张图是我在实际项目中常用的数据探索流程框架,你也可以直接用在工作流里:

信用评分数据探索流程框架 数据加载与清洗 缺失值/异常值诊断 单变量分布分析 目标变量分组统计 相关性分析 (VIF + 热力图) 特征筛选与决策 进入建模阶段 分叉路径可根据业务选择

EDA做到这个程度,你手里基本就有了一张“变量健康检查表”。后面做特征工程和调参时,哪些变量该保留、哪些需要变换、哪些高度冗余,心里都清楚。比起盲目调参,这才是更高效的建模方式。