4. 数据探索性分析(EDA):赔付率分布可视化、时间序列趋势分析、季节性分解
数据探索性分析(EDA)是赔付率尖峰检测的基石。在构建任何检测模型之前,必须通过可视化与统计手段理解赔付率数据的分布形态、长期趋势以及周期性规律。本节将围绕三个核心维度展开:分布可视化、时间序列趋势分析、季节性分解。
4.1 赔付率分布可视化
赔付率(Loss Ratio)通常定义为 已发生赔款 / 已赚保费。其分布特征直接影响尖峰阈值的设定方法。
4.1.1 直方图与核密度估计(KDE)
通过直方图观察赔付率的整体分布形状,判断是否存在明显的右偏(长尾)或多峰特征。KDE 曲线可平滑估计概率密度函数。
关键观察指标:
- 偏度(Skewness): 正偏态(右偏)意味着大部分保单赔付率较低,但存在少数极高赔付率(潜在尖峰)。
- 峰度(Kurtosis): 高峰度(>3)表明数据在均值附近集中,且尾部较厚,尖峰风险更高。
- 异常值区间: 超过 99% 分位数的赔付率值应被标记为候选尖峰。
4.1.2 箱线图与分位数分析
箱线图可直观展示赔付率的中位数、四分位距(IQR)以及异常值。结合分位数表,可量化尖峰的严重程度。
| 分位数 | 正常时期赔付率 | 尖峰时期赔付率 | 偏差幅度 |
|---|---|---|---|
| 25% (Q1) | 0.45 | 0.48 | +6.7% |
| 50% (中位数) | 0.62 | 0.68 | +9.7% |
| 75% (Q3) | 0.78 | 0.92 | +17.9% |
| 99% (阈值) | 1.20 | 1.85 | +54.2% |
| 最大值 | 1.45 | 2.60 | +79.3% |
实践建议: 在 EDA 阶段,建议同时绘制 log 变换后的赔付率分布。对数变换可压缩右偏尾部,使尖峰特征在正态 Q-Q 图上更易识别。
4.2 时间序列趋势分析
赔付率随时间的变化趋势是判断尖峰是否由系统性因素(如费率不足、理赔通胀)引起的核心依据。
4.2.1 滚动统计量(Rolling Statistics)
计算赔付率的滚动均值与滚动标准差,可平滑短期波动,暴露长期趋势。
- 滚动窗口选择: 月度数据通常使用 12 个月窗口(消除年周期);周度数据使用 4 周或 13 周窗口。
- 趋势信号: 当滚动均值持续上升超过 2 个标准差时,提示可能存在结构性趋势变化。
- 尖峰叠加趋势: 若尖峰出现在趋势上升期,需区分是趋势加速还是孤立事件。
4.2.2 趋势分解(Trend Decomposition)
使用 STL(Seasonal-Trend decomposition using LOESS)或移动平均法将时间序列拆解为趋势分量、季节分量和残差分量。
# Python 示例:使用 statsmodels 进行 STL 分解
import pandas as pd
import matplotlib.pyplot as plt
from statsmodels.tsa.seasonal import STL
# 假设 df 包含 'date' 和 'loss_ratio' 列
df['date'] = pd.to_datetime(df['date'])
df = df.set_index('date').asfreq('MS') # 月度频率
stl = STL(df['loss_ratio'], period=12)
result = stl.fit()
# 提取分量
trend = result.trend
seasonal = result.seasonal
residual = result.resid
# 可视化(此处仅展示代码逻辑)
fig, axes = plt.subplots(4, 1, figsize=(12, 8))
df['loss_ratio'].plot(ax=axes[0], title='原始序列')
trend.plot(ax=axes[1], title='趋势分量')
seasonal.plot(ax=axes[2], title='季节分量')
residual.plot(ax=axes[3], title='残差分量')
plt.tight_layout()
plt.show()
注意: 趋势分解假设季节成分是稳定的。若业务存在费率调整、再保结构变化等结构性断点,需先进行断点检测(如 Chow 检验),再分段分解。
4.3 季节性分解
赔付率常受自然季节(如台风季、冬季冰雪)、财务季节(如年末冲业绩)或承保周期影响。季节性分解可量化这些规律,避免将正常季节性波动误判为尖峰。
4.3.1 季节性子序列图(Seasonal Subseries Plot)
将每年同月份(或同季度)的赔付率绘制在同一张图上,可直观对比年际变化与季节模式。
| 月份 | 2021 年 | 2022 年 | 2023 年 | 季节均值 | 季节标准差 |
|---|---|---|---|---|---|
| 1 月 | 0.55 | 0.58 | 0.62 | 0.583 | 0.035 |
| 2 月 | 0.50 | 0.52 | 0.55 | 0.523 | 0.025 |
| 7 月(台风季) | 0.85 | 0.92 | 1.10 | 0.957 | 0.130 |
| 8 月(台风季) | 0.90 | 0.88 | 1.25 | 1.010 | 0.210 |
| 12 月 | 0.60 | 0.65 | 0.68 | 0.643 | 0.040 |
从上表可见,7-8 月(台风季)的季节均值显著高于其他月份,且 2023 年 8 月的赔付率(1.25)超出季节均值 2 个标准差以上,应标记为季节性尖峰候选。
4.3.2 季节调整(Seasonal Adjustment)
通过季节调整剔除可预期的季节波动,使残差序列更清晰地反映异常事件。
# 季节调整:原始值 - 季节分量
seasonally_adjusted = df['loss_ratio'] - seasonal
# 在调整后的序列上检测尖峰
threshold = seasonally_adjusted.mean() + 3 * seasonally_adjusted.std()
spikes = seasonally_adjusted[seasonally_adjusted > threshold]
print(f"季节调整后检测到 {len(spikes)} 个尖峰点")
print(spikes.head())
4.4 EDA 综合输出清单
完成上述分析后,应输出以下关键成果,作为后续建模的输入:
- 分布统计表: 包含均值、中位数、标准差、偏度、峰度、99% 分位数。
- 趋势图: 原始序列 + 滚动均值(12 个月) + 滚动标准差(12 个月)。
- 季节因子表: 每个月份/季度的季节指数(乘性)或季节增量(加性)。
- 残差序列: 剔除趋势和季节后的纯随机波动序列,用于尖峰阈值设定。
- 候选尖峰列表: 基于残差超过 3σ 或 99% 分位数的点,附带时间戳和原始赔付率。
精算实务提示: EDA 不是一次性工作。当业务环境(如新费率表、新再保合约)发生变化时,应重新执行 EDA 以更新季节因子和趋势基线。建议将 EDA 流程封装为自动化报告(如 Quarto 或 Jupyter Notebook),每月自动生成。