第4章 探索性数据分析(EDA):单变量分布、多变量相关性分析、可视化展示
EDA,说白了就是跟数据“聊聊天”。你得先知道每个字段长什么样,彼此之间有没有暧昧关系。我做了这么多年信贷模型,这一步从没跳过——你想想看,数据质量不行,后面全白搭。
4.1 单变量分布分析
拿到一份信用评分卡数据,我习惯先看每个变量的分布。嗯,这里要注意:分类变量和连续变量要分开处理。
4.1.1 连续变量的分布形态
连续变量比如年龄、收入、负债率。我们需要知道它的中心趋势、离散程度,还有——有没有奇怪的“尾巴”。
举个实际例子:我遇到过一份申请数据集,年收入字段中位数才8万,均值却飙到25万。一查,有几个“亿万富翁”填了9999999。这种极端值会拖垮逻辑回归的系数估计,必须处理。
import pandas as pd
import numpy as np
# 假设df是已经加载好的数据集
df = pd.read_csv('credit_data.csv')
# 连续变量描述统计
num_cols = ['age', 'income', 'debt_ratio']
desc = df[num_cols].describe()
print(desc)
我一般还会画直方图+核密度曲线,一眼就能看出是否近似正态。信用评分模型里,很多变量需要做WOE变换,正态性并不是硬要求,但异常值绝对不能忍。
4.1.2 分类变量的频次分布
分类变量,比如婚姻状况、学历、职业。重点看每个类别的样本数量是否悬殊。如果某个类别占比低于5%,可能需要考虑合并。
| 变量 | 类别 | 计数 | 占比 | 坏样本率 |
|---|---|---|---|---|
| 婚姻 | 已婚 | 3200 | 64% | 3.2% |
| 婚姻 | 未婚 | 1500 | 30% | 5.8% |
| 婚姻 | 离异 | 300 | 6% | 9.1% |
4.2 多变量相关性分析
单变量看完了,就得看变量之间有没有“裙带关系”。信用评分卡最烦多重共线性,尤其逻辑回归对这种问题极度敏感。
4.2.1 连续变量相关性矩阵
我习惯用皮尔逊相关系数,阈值一般取0.7。超过0.7的两个变量,我会考虑只保留其中一个,或者做PCA。
# 相关性矩阵
corr_matrix = df[num_cols].corr()
print(corr_matrix)
# 热力图可视化
import seaborn as sns
import matplotlib.pyplot as plt
plt.figure(figsize=(10,8))
sns.heatmap(corr_matrix, annot=True, cmap='RdBu_r', vmin=-1, vmax=1)
plt.title('连续变量相关性热力图')
plt.tight_layout()
plt.show()
这里有个坑:我见过有人把分类变量编码成0/1后直接算皮尔逊相关,结果偏高。如果你有分类变量,建议用卡方检验或Cramer's V。
4.2.2 分类变量与目标变量的关联
我们最关心的是:每个变量跟“是否违约”这个目标有没有关系。对于分类变量,我常用IV(信息量)和WOE来评估。但EDA阶段,先用交叉表+卡方检验快速筛一遍。
# 交叉表与卡方检验
from scipy.stats import chi2_contingency
crosstab = pd.crosstab(df['marital_status'], df['default'])
chi2, p, dof, expected = chi2_contingency(crosstab)
print(f"卡方值: {chi2:.2f}, p值: {p:.4f}")
4.3 可视化展示
可视化不是用来发朋友圈的。一张好图能帮你发现数据问题,比如:
- 箱线图暴露异常值
- 分布重叠看区分度
- 散点矩阵看非线性关系
4.3.1 连续变量:箱线图+分布图
# 箱线图(按目标变量分组)
plt.figure(figsize=(12,5))
plt.subplot(1,2,1)
sns.boxplot(x='default', y='income', data=df)
plt.title('收入分布 vs 违约情况')
plt.subplot(1,2,2)
sns.histplot(data=df, x='debt_ratio', hue='default', kde=True, alpha=0.5)
plt.title('负债率分布(按违约分组)')
plt.tight_layout()
plt.show()
我经常在箱线图上发现“违约人群的收入中位数明显低于正常人群”,这种变量后面大概率能进评分卡。
4.3.2 分类变量:堆叠柱状图
# 堆叠柱状图:看各婚姻状态内的违约比例
pd.crosstab(df['marital_status'], df['default'], normalize='index').plot.bar(stacked=True)
plt.title('不同婚姻状态违约比例')
plt.ylabel('占比')
plt.xticks(rotation=45)
plt.legend(title='违约')
plt.tight_layout()
plt.show()
4.4 EDA流程总览(SVG图)
下面这张图总结了EDA的核心步骤:先单变量后多变量,用可视化辅助判断。
4.5 实操建议
做EDA的时候,我建议你开一个Jupyter Notebook,把所有发现记录成markdown。信用评分卡项目后期需要写报告,这些笔记就是第一手素材。
eda_output/存放图表,eda_summary/存放字段分析备忘录。回头查找问题的时候效率翻倍。
嗯,EDA这步千万别着急。我记得有个项目,因为没发现“教育年限”字段里出现了999这个缺失替代值,导致后面分箱全乱套。花一天时间认真探索数据,能省你后面一周的返工时间。