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 回归),而非直接修正数据。
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 数据清洗质量检查清单
- 完整性: 各字段缺失比例是否在可接受范围内?关键字段是否已填充?
- 一致性: 字段格式是否统一(如日期格式、货币单位)?关联键是否无重复或丢失?
- 准确性: 异常值是否已识别并修正?业务规则是否已应用(如赔付金额 ≤ 保额)?
- 时效性: 数据时间窗口是否覆盖建模所需周期?是否存在未来数据泄露?
完成数据准备与清洗后,即可进入特征工程阶段,将原始数据转化为模型可用的预测变量。