4. 数据探索与可视化:数据概览、缺失值分布、异常值检测、单变量分布可视化
数据探索与可视化(Exploratory Data Analysis, EDA)是构建风控模型前最关键的一步。对于组合风险人群切片任务,EDA 的目标不仅是了解数据全貌,更要发现不同风险切片之间的特征差异、数据质量问题以及潜在的建模陷阱。本章将使用 matplotlib 和 seaborn 作为可视化工具,系统性地完成数据概览、缺失值分析、异常值检测与单变量分布可视化。
4.1 数据概览:快速掌握数据集全貌
在加载数据后,首先通过以下核心方法获取数据集的整体信息:
| 方法 | 功能 | 关键输出 |
|---|---|---|
df.head() |
查看前5行样本 | 字段名、样本值、数据类型初步判断 |
df.info() |
列级非空计数与数据类型 | 总行数、每列非空数、Dtype(int/float/object) |
df.describe() |
数值型字段的统计摘要 | 均值、标准差、四分位数、最大/最小值 |
df.nunique() |
每列唯一值数量 | 识别高基数类别特征与常量特征 |
实战要点: 在组合风险切片场景中,务必检查
df['risk_segment'] 的分布。如果某个切片样本量过少(如 < 500 条),后续建模时需考虑分层采样或过采样策略。
import pandas as pd
import numpy as np
# 加载组合风险人群数据(示例)
df = pd.read_csv('risk_combination_data.csv')
# 数据概览
print("数据集形状:", df.shape)
print("\n前5行样本:")
print(df.head())
print("\n数据信息:")
df.info()
print("\n数值字段统计摘要:")
print(df.describe())
print("\n各列唯一值数量:")
print(df.nunique())
4.2 缺失值分布:定位数据空洞
缺失值在风控数据中极为常见,尤其是收入、负债率、历史逾期天数等敏感字段。缺失并非随机,往往与用户的风险等级相关。我们需要从两个维度分析缺失值:全局缺失率 和 按风险切片的缺失差异。
4.2.1 全局缺失率矩阵
# 计算缺失率并排序
missing_ratio = df.isnull().mean().sort_values(ascending=False)
missing_df = pd.DataFrame({'缺失率': missing_ratio})
missing_df = missing_df[missing_df['缺失率'] > 0]
print("字段缺失率(仅显示有缺失的字段):")
print(missing_df)
4.2.2 按风险切片对比缺失模式
不同风险切片(如“高收入-高负债-低逾期” vs “低收入-低负债-高逾期”)的缺失模式可能截然不同。例如,高逾期人群的“收入”字段缺失率可能显著高于低逾期人群,这本身就是一种风险信号。
# 按风险切片分组计算缺失率
segment_missing = df.groupby('risk_segment').apply(
lambda x: x.isnull().mean()
).T
# 筛选缺失率 > 0.1 的字段
high_missing_fields = segment_missing.loc[
segment_missing.max(axis=1) > 0.1
]
print("高风险切片缺失率对比(缺失率 > 10% 的字段):")
print(high_missing_fields)
处理建议: 对于缺失率 > 50% 的字段,建议直接删除;对于缺失率在 10%-50% 之间的字段,优先使用 LightGBM 的原生缺失值处理能力(
use_missing=false 时自动将缺失值分到最优节点);对于缺失率 < 10% 的字段,可使用中位数或众数填充。
4.3 异常值检测:识别极端样本
风控数据中的异常值可能代表欺诈行为、数据录入错误或极端信用事件。常用的检测方法包括 IQR 规则 和 Z-Score 方法。对于组合风险切片,异常值检测应分层进行,因为不同切片的正常值范围可能差异巨大。
| 方法 | 适用场景 | 阈值 | 注意事项 |
|---|---|---|---|
| IQR 规则 | 偏态分布、有离群点 | 下界: Q1 - 1.5×IQR 上界: Q3 + 1.5×IQR |
对长尾分布敏感,可调整系数为 3.0 |
| Z-Score | 近似正态分布 | |Z| > 3 | 受极端值影响大,建议使用稳健 Z-Score |
| 分位数截断 | 所有分布 | 上下 0.5% 或 1% | 简单粗暴,适合大规模数据预处理 |
# 使用 IQR 规则检测异常值(按风险切片分层)
def detect_outliers_iqr(group, column, multiplier=1.5):
Q1 = group[column].quantile(0.25)
Q3 = group[column].quantile(0.75)
IQR = Q3 - Q1
lower_bound = Q1 - multiplier * IQR
upper_bound = Q3 + multiplier * IQR
return (group[column] < lower_bound) | (group[column] > upper_bound)
# 对 'income' 字段按风险切片检测异常
df['income_outlier'] = df.groupby('risk_segment').apply(
lambda g: detect_outliers_iqr(g, 'income', multiplier=1.5)
).reset_index(level=0, drop=True)
print("各切片异常值数量:")
print(df.groupby('risk_segment')['income_outlier'].sum())
避坑指南: 不要在全量数据上统一使用 IQR 规则。例如,“高收入”切片的正常收入范围可能是 50k-200k,而“低收入”切片是 10k-40k。统一阈值会导致“低收入”切片中 45k 的样本被误判为异常,而“高收入”切片中 250k 的样本却被视为正常。
4.4 单变量分布可视化
单变量分布可视化帮助我们理解每个特征的取值分布、偏态、峰度以及在不同风险切片下的分离度。本节使用 matplotlib 和 seaborn 绘制直方图、箱线图和核密度估计图。
4.4.1 数值型特征:直方图 + KDE
import matplotlib.pyplot as plt
import seaborn as sns
# 设置中文字体
plt.rcParams['font.sans-serif'] = ['SimHei']
plt.rcParams['axes.unicode_minus'] = False
# 选择关键数值特征
num_features = ['income', 'debt_ratio', 'overdue_days', 'credit_score']
fig, axes = plt.subplots(2, 2, figsize=(14, 10))
axes = axes.flatten()
for i, feat in enumerate(num_features):
sns.histplot(data=df, x=feat, hue='risk_segment',
kde=True, bins=50, alpha=0.6, ax=axes[i])
axes[i].set_title(f'{feat} 分布(按风险切片)')
axes[i].set_xlabel(feat)
axes[i].set_ylabel('频数')
plt.tight_layout()
plt.show()
4.4.2 类别型特征:柱状图
# 选择关键类别特征
cat_features = ['education_level', 'employment_type', 'marital_status']
fig, axes = plt.subplots(1, 3, figsize=(18, 5))
axes = axes.flatten()
for i, feat in enumerate(cat_features):
# 计算每个类别在各风险切片中的占比
cross_tab = pd.crosstab(df[feat], df['risk_segment'], normalize='index')
cross_tab.plot(kind='bar', stacked=True, ax=axes[i], colormap='Set2')
axes[i].set_title(f'{feat} 风险切片占比')
axes[i].set_xlabel(feat)
axes[i].set_ylabel('比例')
axes[i].legend(title='风险切片', bbox_to_anchor=(1.05, 1))
plt.tight_layout()
plt.show()
4.5 数据探索流程总览
以下 SVG 图展示了从原始数据到可视化洞察的完整流程,包含数据加载、概览、缺失分析、异常检测和分布可视化五个核心阶段,以及每个阶段的输出产物。
4.6 可视化洞察与建模决策
完成上述探索后,应形成以下关键决策清单:
- 特征筛选: 删除缺失率 > 50% 的字段;删除唯一值数量为 1 的常量特征。
- 缺失处理策略: 对缺失率 10%-50% 的字段,保留原始值并让 LightGBM 自动处理;对缺失率 < 10% 的字段,使用切片内中位数填充。
- 异常值处理: 对 IQR 规则检测到的极端值,进行截断(winsorize)而非删除,避免损失切片内稀有样本。
- 特征工程方向: 根据分布可视化结果,对偏态严重的特征(如收入、逾期天数)进行对数变换或 Box-Cox 变换;对在风险切片间分布差异明显的特征,优先用于模型训练。
- 切片验证: 如果某个风险切片的样本量 < 500,考虑将该切片与最相似的相邻切片合并,或使用分层交叉验证。
课程核心提示: 数据探索不是一次性工作。在后续特征工程和模型调优过程中,应反复回到 EDA 阶段验证新特征的分布合理性。组合风险切片场景的特殊性在于:每个切片都可能拥有独特的分布特征,全局统计量往往会掩盖切片间的异质性。始终牢记“按切片分层探索”这一原则。