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 图展示了从原始数据到可视化洞察的完整流程,包含数据加载、概览、缺失分析、异常检测和分布可视化五个核心阶段,以及每个阶段的输出产物。

数据探索与可视化流程总览 阶段1: 数据加载 pd.read_csv() 阶段2: 数据概览 shape / info / describe 阶段3: 缺失值分析 缺失率 / 切片对比 阶段4: 异常值检测 IQR / Z-Score 阶段5: 分布可视化 直方图 / 箱线图 / KDE 各阶段输出产物 • 阶段1: 原始 DataFrame • 阶段2: 字段统计表、数据类型清单、唯一值报告 • 阶段3: 缺失率矩阵、切片缺失对比表 • 阶段4: 异常值标记列、异常率统计 • 阶段5: 分布可视化图表(直方图/箱线图/KDE)

4.6 可视化洞察与建模决策

完成上述探索后,应形成以下关键决策清单:

  • 特征筛选: 删除缺失率 > 50% 的字段;删除唯一值数量为 1 的常量特征。
  • 缺失处理策略: 对缺失率 10%-50% 的字段,保留原始值并让 LightGBM 自动处理;对缺失率 < 10% 的字段,使用切片内中位数填充。
  • 异常值处理: 对 IQR 规则检测到的极端值,进行截断(winsorize)而非删除,避免损失切片内稀有样本。
  • 特征工程方向: 根据分布可视化结果,对偏态严重的特征(如收入、逾期天数)进行对数变换或 Box-Cox 变换;对在风险切片间分布差异明显的特征,优先用于模型训练。
  • 切片验证: 如果某个风险切片的样本量 < 500,考虑将该切片与最相似的相邻切片合并,或使用分层交叉验证。
课程核心提示: 数据探索不是一次性工作。在后续特征工程和模型调优过程中,应反复回到 EDA 阶段验证新特征的分布合理性。组合风险切片场景的特殊性在于:每个切片都可能拥有独特的分布特征,全局统计量往往会掩盖切片间的异质性。始终牢记“按切片分层探索”这一原则。