2. 数据准备与清洗:数据源类型、缺失值处理、异常值检测与修正

在精算建模中,数据质量直接决定赔付率预测的可靠性。本章聚焦于数据源的识别、缺失值处理策略以及异常值的检测与修正,为后续特征工程与模型训练奠定基础。

2.1 数据源类型

精算模型通常依赖三类数据源,每类数据在赔付率预测中扮演不同角色:

数据源类型 典型字段 在赔付率预测中的作用
保单数据 投保人年龄、性别、车型、保额、免赔额、保险期限 刻画风险暴露与定价因子,是模型的基础特征
理赔数据 出险时间、赔付金额、事故类型、结案状态 提供历史赔付记录,用于计算实际赔付率与损失分布
外部数据 地区经济指数、天气数据、驾驶行为评分、信用评分 补充内部数据未覆盖的风险维度,提升模型区分度
实践提示: 在整合多源数据时,务必以 保单ID 或 客户ID 作为主键进行关联,并检查关联后的记录数是否合理,避免因数据膨胀或丢失导致偏差。
精算模型数据源融合架构 精算模型数据源融合架构 保单数据 投保人/车辆/保单信息 理赔数据 出险/赔付/结案记录 外部数据 经济/天气/行为评分 数据融合与清洗层 建模数据集(赔付率预测)

2.2 缺失值处理

缺失值是数据清洗中最常见的问题。处理策略需结合缺失机制与业务含义:

2.2.1 缺失机制分类

  • 完全随机缺失(MCAR): 缺失与数据本身无关,可直接删除或简单填充。
  • 随机缺失(MAR): 缺失与其他观测变量相关,需借助模型预测填充。
  • 非随机缺失(MNAR): 缺失与未观测到的因素相关,处理难度最大,需业务干预。

2.2.2 常用处理方法

方法 适用场景 优点 缺点
删除缺失记录 缺失比例 < 5%,且为 MCAR 简单快速 可能损失有效样本
均值/中位数填充 数值型特征,缺失比例较低 计算量小 降低方差,可能引入偏差
众数填充 分类型特征 保持分布 可能过度代表某一类别
KNN 填充 特征间存在相关性 利用相似样本信息 计算成本高,对 K 值敏感
模型预测填充 缺失值作为目标变量 精度较高 可能引入模型偏差
精算场景建议: 对于赔付率建模中的关键字段(如赔付金额、出险次数),若缺失比例超过 30%,建议优先排查数据采集流程,而非机械填充。对于免赔额等定价因子,可考虑用“未知”类别单独编码。

2.3 异常值检测与修正

异常值会严重扭曲赔付率模型的参数估计与预测能力。检测方法需结合业务逻辑与统计技术。

2.3.1 检测方法对比

方法 原理 适用数据类型 精算典型应用
Z-Score 法 计算与均值的标准差倍数 近似正态分布 检测异常高的赔付金额
IQR 四分位距法 超出 Q1-1.5IQR 或 Q3+1.5IQR 偏态分布 检测出险次数异常
孤立森林 基于随机切割的异常隔离 高维数据 多特征联合异常检测
业务规则 基于领域知识设定阈值 所有类型 赔付金额 > 保额、年龄为负值

2.3.2 修正策略

  • 截尾处理(Winsorization): 将异常值替换为指定百分位数的值(如 99% 分位数),保留样本量。
  • 标记为缺失: 将异常值视为缺失,再按缺失值方法处理,适用于明显录入错误。
  • 分箱处理: 将连续变量离散化,异常值归入最边缘箱体,减少极端值影响。
  • 模型稳健化: 使用对异常值不敏感的模型(如树模型、Huber 回归),而非直接修正数据。
异常值检测与修正流程 异常值检测与修正流程 原始数据输入 异常值检测方法选择 Z-Score 法 | IQR 法 | 孤立森林 | 业务规则 截尾处理 标记为缺失 分箱处理 清洗后数据输出

2.4 数据清洗代码示例

以下 Python 代码演示了缺失值填充与异常值检测的典型操作:

import pandas as pd
import numpy as np

# 加载示例数据
df = pd.read_csv('claim_data.csv')

# 缺失值处理:对数值型字段用中位数填充
num_cols = ['claim_amount', 'vehicle_age', 'driver_age']
for col in num_cols:
    df[col].fillna(df[col].median(), inplace=True)

# 缺失值处理:对分类型字段用众数填充
cat_cols = ['vehicle_type', 'region']
for col in cat_cols:
    df[col].fillna(df[col].mode()[0], inplace=True)

# 异常值检测:IQR 法
Q1 = df['claim_amount'].quantile(0.25)
Q3 = df['claim_amount'].quantile(0.75)
IQR = Q3 - Q1
lower_bound = Q1 - 1.5 * IQR
upper_bound = Q3 + 1.5 * IQR

# 标记异常值
df['claim_amount_outlier'] = ((df['claim_amount'] < lower_bound) |
                              (df['claim_amount'] > upper_bound)).astype(int)

# 异常值修正:截尾处理(Winsorization)
df['claim_amount_winsorized'] = df['claim_amount'].clip(lower=lower_bound,
                                                        upper=upper_bound)

print(f"异常值数量: {df['claim_amount_outlier'].sum()}")
print(f"修正后数据范围: {df['claim_amount_winsorized'].min():.2f} - "
      f"{df['claim_amount_winsorized'].max():.2f}")
注意: 异常值检测的阈值(如 IQR 的 1.5 倍系数)并非固定不变。在精算场景中,对于高损失尾部数据,可适当放宽阈值(如使用 3 倍 IQR),避免过度剔除真实的大额赔付记录。

2.5 数据清洗质量检查清单

  • 完整性: 各字段缺失比例是否在可接受范围内?关键字段是否已填充?
  • 一致性: 字段格式是否统一(如日期格式、货币单位)?关联键是否无重复或丢失?
  • 准确性: 异常值是否已识别并修正?业务规则是否已应用(如赔付金额 ≤ 保额)?
  • 时效性: 数据时间窗口是否覆盖建模所需周期?是否存在未来数据泄露?

完成数据准备与清洗后,即可进入特征工程阶段,将原始数据转化为模型可用的预测变量。