4. 数据采集与预处理:从数据库/API获取保单与理赔数据、处理缺失值、异常值检测与处理
实时赔付率预测模型的质量高度依赖输入数据的完整性与准确性。本章聚焦于从生产环境采集原始保单与理赔数据,并完成缺失值填充、异常值识别与清洗,为后续特征工程与模型训练奠定可靠基础。
4.1 数据源与采集策略
实时赔付率模型通常需要融合两类核心数据源:保单主数据(静态属性)与理赔流水数据(动态事件)。采集方式根据系统架构分为数据库直连与API流式接入。
| 数据源类型 | 典型表/接口 | 关键字段示例 | 采集频率 |
|---|---|---|---|
| 保单主数据 | policy_info | policy_id, product_code, underwrite_date, premium, sum_insured, risk_level | 每日批量(T+1) |
| 理赔流水数据 | claim_transaction | claim_id, policy_id, claim_date, claim_amount, claim_type, status | 实时/准实时(Kafka/API) |
| 历史赔付率聚合 | loss_ratio_agg | policy_id, period, earned_premium, incurred_loss, loss_ratio | 每日批量 |
生产环境建议:对于实时预测场景,理赔数据应优先通过消息队列(如Kafka)或REST API接入,避免频繁直连OLTP数据库造成锁表或性能抖动。保单主数据变化频率低,可采用每日增量同步。
4.2 数据采集流程架构
下图展示了从数据源到预处理模块的标准化采集管道,包含批处理与流处理两条路径。
4.3 缺失值处理策略
保单与理赔数据中常见的缺失场景包括:理赔金额未录入、风险等级缺失、保单生效日期为空等。不同字段的缺失机制与业务含义不同,需采用差异化填充策略。
| 字段 | 缺失率典型范围 | 缺失原因 | 推荐处理方法 |
|---|---|---|---|
| claim_amount | 5% – 15% | 理赔未结案、人工录入遗漏 | 按险种+地区分组中位数填充 |
| risk_level | 2% – 8% | 新客户未评级、系统迁移丢失 | 众数填充或标记为“未知”类别 |
| underwrite_date | < 1% | 数据接口异常 | 使用policy_effective_date回填 |
| claim_type | 3% – 10% | 理赔分类未更新 | 模型预测分类或标记为“其他” |
关键原则:对于实时预测场景,缺失值处理必须在线性时间内完成,避免使用迭代算法。推荐预计算分组统计量(如均值、中位数)并存入查找表,在预处理阶段直接映射填充。
4.4 异常值检测与处理
赔付率相关数据中,异常值通常表现为:理赔金额远超正常范围、保单保费为负值、理赔日期早于保单生效日期等。异常值会严重扭曲模型训练,必须系统化检测与处理。
4.4.1 异常值检测方法对比
| 方法 | 适用场景 | 优点 | 缺点 |
|---|---|---|---|
| Z-Score(3σ) | 近似正态分布的连续变量 | 计算简单,可解释性强 | 对偏态分布不鲁棒 |
| IQR(四分位距) | 偏态分布、含离群点的数据 | 不受极端值影响 | 阈值选择较主观 |
| 孤立森林 | 高维数据、非监督场景 | 线性时间复杂度,适合实时 | 对局部异常不敏感 |
| 业务规则 | 强约束字段(如保费>0) | 零误报,符合监管要求 | 无法发现未知异常模式 |
4.4.2 异常值处理流程
下图展示了从检测到处理的完整决策链路,确保异常值被合理识别并处置。
4.5 数据预处理代码示例
以下Python代码片段展示了使用Pandas对保单数据进行缺失值填充与异常值检测的典型实现,可直接嵌入实时预处理管道。
import pandas as pd
import numpy as np
# 加载原始保单与理赔数据
policy_df = pd.read_parquet('policy_data.parquet')
claim_df = pd.read_parquet('claim_data.parquet')
# 合并为宽表
merged_df = pd.merge(policy_df, claim_df, on='policy_id', how='left')
# ========== 缺失值处理 ==========
# 按险种分组中位数填充理赔金额
claim_median = merged_df.groupby('product_code')['claim_amount'].transform('median')
merged_df['claim_amount'].fillna(claim_median, inplace=True)
# 风险等级众数填充
risk_mode = merged_df['risk_level'].mode()[0]
merged_df['risk_level'].fillna(risk_mode, inplace=True)
# ========== 异常值检测(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
return (series < lower_bound) | (series > upper_bound)
# 对理赔金额进行异常标记
merged_df['claim_amount_outlier'] = detect_outliers_iqr(merged_df['claim_amount'])
# 异常值截尾处理(替换为上下限)
upper_limit = merged_df['claim_amount'].quantile(0.95)
lower_limit = merged_df['claim_amount'].quantile(0.05)
merged_df['claim_amount'] = merged_df['claim_amount'].clip(lower_limit, upper_limit)
# 输出清洗后数据
merged_df.to_parquet('cleaned_data.parquet', index=False)
print(f"清洗完成,共处理 {len(merged_df)} 条记录,异常值占比 {merged_df['claim_amount_outlier'].mean():.2%}")
实时场景注意:上述代码中的groupby操作在超大规模数据(千万级)上可能产生延迟。生产环境建议使用Spark或Flink进行分布式预处理,并将分组统计量预计算后广播到各工作节点。
4.6 数据质量监控指标
在预处理管道上线后,需要持续监控数据质量,确保模型输入稳定。以下为关键监控指标及其告警阈值。
| 监控指标 | 计算方式 | 正常范围 | 告警阈值 |
|---|---|---|---|
| 缺失率 | 缺失值数量 / 总记录数 | < 5% | > 10% |
| 异常值占比 | 标记为异常的记录数 / 总记录数 | < 3% | > 8% |
| 数据延迟 | 最新记录时间戳与当前时间差 | < 30分钟 | > 2小时 |
| 字段完整性 | 必填字段非空比例 | 100% | < 99% |
最佳实践:将数据质量监控与模型预测结果联动。当某时段缺失率或异常值占比突增时,自动触发模型回滚至上一版本,并发送告警给数据工程团队,避免劣质数据影响赔付率预测准确性。