4. 数据探索性分析(EDA):描述性统计、缺失值分布、异常值初步识别

在构建贷后预警模型之前,必须对原始数据进行系统性的探索性分析。本章将围绕描述性统计、缺失值分布和异常值初步识别三个核心任务展开,为后续特征工程与模型训练奠定数据基础。

4.1 描述性统计:快速掌握数据全貌

描述性统计帮助我们理解各字段的集中趋势、离散程度与分布形态。以下为贷后预警数据集关键字段的统计摘要:

字段名称 数据类型 非空计数 均值 标准差 最小值 25%分位 50%分位 75%分位 最大值
贷款金额(元) float64 100,000 85,432.10 120,345.67 1,000 20,000 50,000 100,000 5,000,000
逾期天数 int64 100,000 15.23 32.45 0 0 3 18 365
客户年龄 int64 99,850 38.56 10.21 18 30 37 45 85
近6月查询次数 int64 100,000 8.12 6.78 0 3 6 11 50
收入负债比 float64 97,200 0.45 0.28 0.01 0.22 0.40 0.62 2.50
关键发现:贷款金额与逾期天数呈现右偏分布(均值远大于中位数),说明存在少量高额贷款和长期逾期样本,需在后续建模中关注长尾效应。

4.2 缺失值分布:识别数据空洞

缺失值会直接影响模型训练质量。我们按字段统计缺失率,并分析缺失模式:

字段名称 缺失数量 缺失率 缺失类型 初步处理建议
客户年龄 150 0.15% 随机缺失 中位数填充
收入负债比 2,800 2.80% 非随机缺失(可能与收入低相关) 模型预测填充或单独编码
工作单位类型 5,300 5.30% 随机缺失 众数填充 + 新增“未知”类别
担保人收入 12,000 12.00% 结构缺失(无担保人时为空) 填充0并新增“有无担保人”标志
历史最大逾期金额 1,050 1.05% 随机缺失 中位数填充
处理原则:缺失率低于1%的字段可直接用中位数/众数填充;缺失率在1%-5%之间的字段需分析缺失机制;缺失率超过5%的字段建议构造“是否缺失”标志变量,再结合业务逻辑填充。

4.3 异常值初步识别:箱线图与业务规则

异常值会扭曲模型学习方向,需结合统计方法与业务知识进行初步筛查。以下为关键字段的异常值识别规则:

  • 贷款金额:超过均值+3倍标准差(约446,469元)或低于1,000元视为异常。
  • 逾期天数:超过365天视为数据录入错误或极端案例,需单独处理。
  • 收入负债比:大于1.5视为异常(收入无法覆盖负债),需核实数据源。
  • 近6月查询次数:超过30次视为频繁查询,可能为多头借贷信号,但非数据错误,保留为特征。
  • 客户年龄:小于18岁或大于80岁视为异常,需剔除或修正。
注意:异常值不等于错误值。部分异常值(如高查询次数、高收入负债比)可能包含重要的风险信号,应在建模前与业务方确认是否保留或单独编码。

4.4 EDA 流程总览

以下 SVG 图展示了贷后预警数据 EDA 的完整流程,从原始数据输入到最终输出清洗后的数据集:

贷后预警数据 EDA 流程总览 原始数据 描述性统计 缺失值分布分析 异常值初步识别 数据清洗与填充决策 清洗后数据集

4.5 代码实现:EDA 核心步骤

以下代码展示了使用 Python 进行描述性统计、缺失值分析和异常值识别的标准流程:

import pandas as pd
import numpy as np

# 加载数据
df = pd.read_csv('loan_early_warning.csv')

# 1. 描述性统计
desc_stats = df.describe(percentiles=[0.25, 0.5, 0.75])
print("描述性统计结果:")
print(desc_stats)

# 2. 缺失值分布
missing_counts = df.isnull().sum()
missing_rates = (df.isnull().sum() / len(df)) * 100
missing_df = pd.DataFrame({
    '缺失数量': missing_counts,
    '缺失率(%)': missing_rates.round(2)
})
missing_df = missing_df[missing_df['缺失数量'] > 0].sort_values('缺失率(%)', ascending=False)
print("\n缺失值分布:")
print(missing_df)

# 3. 异常值初步识别(基于IQR方法)
def detect_outliers_iqr(series):
    Q1 = series.quantile(0.25)
    Q3 = series.quantile(0.75)
    IQR = Q3 - Q1
    lower_bound = Q1 - 1.5 * IQR
    upper_bound = Q3 + 1.5 * IQR
    outliers = series[(series < lower_bound) | (series > upper_bound)]
    return len(outliers), lower_bound, upper_bound

numeric_cols = ['贷款金额', '逾期天数', '客户年龄', '近6月查询次数', '收入负债比']
print("\n异常值初步识别(IQR方法):")
for col in numeric_cols:
    count, lb, ub = detect_outliers_iqr(df[col])
    print(f"{col}: 异常值数量={count}, 下界={lb:.2f}, 上界={ub:.2f}")
输出解读:描述性统计揭示了数据的分布形态与潜在偏态;缺失值分布表帮助确定填充策略;异常值识别结果需结合业务规则进行二次确认,避免误删有效风险信号。