4. 数据准备与清洗
在保险费率表构建与Rating Plan落地的整个工程链条中,数据准备与清洗往往占据60%以上的工作量,却最容易被低估。费率表本质上是“风险因子—费率值”的映射矩阵,而这张矩阵的每一个单元格都来自历史赔付、承保、再保与外部数据。如果输入数据存在来源混乱、缺失、异常或量纲不统一,后续无论使用GLM、GBM还是评分卡,都会得到“垃圾进、垃圾出”的结果。本节围绕数据来源、缺失值处理、异常值识别、数据标准化四个环节,给出可落地的工程方法。
一、核心原理:数据质量决定费率表的可信边界
费率表构建对数据的要求可以概括为三个维度:完整性(每条风险记录的关键因子是否齐全)、一致性(同一因子在不同系统、不同时间口径是否统一)、代表性(样本是否覆盖目标客群与风险分布)。数据清洗不是“把脏数据删掉”,而是通过可追溯的规则,把原始数据转化为可建模、可解释、可审计的建模宽表。其核心原则是:清洗规则必须可复现、可版本化、可回溯到原始记录,否则费率表在监管或再保审核时无法自证。
二、数据来源:多源异构数据的整合策略
车险、健康险、财产险的费率表数据通常来自以下五类源系统,整合时需要明确主键、时间口径与责任范围:
- 承保系统:保单号、被保险人、标的、保额、保费、起保止期、渠道、折扣系数。
- 理赔系统:赔案号、出险时间、报案时间、立案金额、已决/未决金额、责任类型。
- 再保/共保系统:分出比例、摊回金额、再保层结构。
- 外部数据:行业经验赔付率、车型零整比、地区风险系数、征信或健康评分。
- 精算中间表:风险暴露量、已赚保费、赔付率、案均赔款。
整合时建议以“保单—标的—赔案”三级粒度建立主键,并统一时间口径为事故年或保单年。例如,用SQL将理赔数据按事故年汇总到标的粒度:
SELECT policy_id, item_id,
SUM(CASE WHEN accident_year = 2023 THEN paid_loss ELSE 0 END) AS loss_2023,
COUNT(DISTINCT claim_id) AS claim_cnt_2023
FROM claim_fact
GROUP BY policy_id, item_id;
三、缺失值处理:从“删”到“补”再到“标记”
缺失值处理的第一步是诊断缺失机制:完全随机缺失(MCAR)、随机缺失(MAR)还是非随机缺失(MNAR)。费率表中常见的缺失包括:新车无历史赔付、客户未填写职业、外部数据未匹配到车型。处理策略按缺失比例分层:
| 缺失比例 | 推荐策略 | 风险提示 |
|---|---|---|
| < 5% | 删除记录或均值/中位数填充 | 需确认缺失随机,避免样本偏差 |
| 5%~20% | 分组填充、模型预测填充、增加“缺失”哑变量 | 哑变量可保留缺失信息,防止信息丢失 |
| > 20% | 重新评估该因子是否可用,或单独建缺失层 | 高缺失因子直接入模会放大噪声 |
在费率表中,缺失值本身可能携带风险信号。例如“职业未知”的客户,其赔付经验可能显著高于“职业明确”的客户。因此,推荐做法是将缺失作为一个独立类别,而不是简单填充。代码示例:
import pandas as pd
df['occupation'] = df['occupation'].fillna('UNKNOWN')
df['vehicle_age_missing'] = df['vehicle_age'].isna().astype(int)
df['vehicle_age'] = df.groupby('vehicle_type')['vehicle_age'].transform(
lambda x: x.fillna(x.median())
)
四、异常值识别与数据标准化
异常值识别要区分“错误数据”与“真实极端风险”。错误数据如年龄为200岁、保额为负数,应直接修正或剔除;真实极端值如高额赔案,应保留但做截断(Winsorize)或分层处理。常用方法包括:
- 统计法:Z-score > 3、IQR 超出1.5倍四分位距。
- 业务规则法:年龄不在0~120、车龄为负、保费为0但保额为正。
- 模型法:孤立森林、DBSCAN、分位数回归残差。
数据标准化则解决量纲与分布问题。费率表中连续变量(如年龄、车龄、保额)常需分箱或标准化。标准化方法包括Min-Max、Z-score、Robust Scaling,以及针对偏态分布的分位数映射。例如,将赔付率按分位数映射到0~1区间,便于评分卡转换:
from sklearn.preprocessing import QuantileTransformer
qt = QuantileTransformer(n_quantiles=1000, output_distribution='uniform')
df['loss_ratio_scaled'] = qt.fit_transform(df[['loss_ratio']])
五、案例与复盘:一个车险费率表的数据清洗实战
某车险公司构建“车型—地区—年龄”三维费率表时,发现模型AUC仅0.58。复盘发现三个问题:一是理赔数据按“报案年”而非“事故年”汇总,导致赔付率被低估;二是“车龄”缺失率18%,直接删除后样本偏向新车;三是“地区”编码在承保与理赔系统中不一致,导致匹配失败。修正后:统一事故年口径、将车龄缺失标记为独立层、建立地区编码映射表,AUC提升至0.67,费率表区分度显著改善。
总结来看,数据准备与清洗是费率表构建的“地基工程”。数据来源决定口径,缺失值处理决定信息保留度,异常值识别决定模型稳健性,数据标准化决定因子可比性。四者环环相扣,任何一环的偷工减料都会在Rating Plan落地时以“费率不敏感”“赔付率倒挂”“监管问询”等形式暴露。建议团队建立标准化的清洗流水线,把每一步规则固化为可执行脚本与日志,让费率表不仅“算得准”,更“说得清”。