3. 特征工程基础:特征构造与选择

特征工程是精算模型从原始数据到预测能力的桥梁。在赔付率预测场景中,原始保单、理赔、承保数据往往以宽表或事件序列形式存在,必须通过系统的构造与筛选,才能转化为模型可用的高信息密度特征。本章聚焦于特征构造的三大方法(聚合、比率、时间窗口)与特征选择的两大核心手段(IV值、相关性分析)。

核心观点: 特征工程不是一次性工作,而是与模型评估迭代进行的循环过程。好的特征能显著提升模型对赔付风险的区分能力,同时降低过拟合风险。

3.1 特征构造方法

特征构造的目标是从原始字段中衍生出更能刻画风险本质的新变量。精算领域最常用的三类构造方法为:聚合特征、比率特征和时间窗口特征。

3.1.1 聚合特征

聚合特征通过对个体或群体在某个维度上的统计量进行汇总得到,常用于刻画历史行为模式。在赔付率预测中,常见的聚合维度包括:保单号、客户ID、车型、地区、渠道等。

聚合维度 聚合函数 典型应用场景
客户ID COUNT, SUM, AVG, MAX, MIN 历史出险次数、累计赔付金额、平均赔付额
车型 AVG, STD, MEDIAN 该车型平均赔付率、赔付波动性
地区/渠道 SUM, RATE 地区总赔付额、渠道赔付率
时间(月/季) LAG, DIFF, PCT_CHANGE 赔付率环比变化、季节性波动
# Python 示例:客户维度聚合特征构造
import pandas as pd

# 假设 claim_df 为理赔明细表,包含 policy_id, claim_amount, claim_date
claim_agg = claim_df.groupby('policy_id').agg(
    claim_count=('claim_id', 'count'),
    total_claim_amount=('claim_amount', 'sum'),
    avg_claim_amount=('claim_amount', 'mean'),
    max_claim_amount=('claim_amount', 'max'),
    last_claim_date=('claim_date', 'max')
).reset_index()

# 合并回保单主表
policy_df = policy_df.merge(claim_agg, on='policy_id', how='left')

3.1.2 比率特征

比率特征通过两个或多个相关字段的比值来消除量纲影响,反映相对风险水平。在精算模型中,比率特征往往比绝对值更具稳定性和可解释性。

  • 赔付率 = 赔付金额 / 已赚保费:最核心的比率特征,直接衡量承保盈利水平。
  • 案均赔付 = 赔付金额 / 出险次数:反映单次事故的严重程度。
  • 出险频率 = 出险次数 / 保单数:衡量风险发生的概率。
  • 费用率 = 运营费用 / 保费收入:评估运营效率。
  • 续保率 = 续保客户数 / 到期客户数:反映客户留存与风险选择。
精算提示: 构造比率特征时需注意分母不能为零或过小,否则会导致特征值不稳定。建议对分母设置最小阈值(如 0.01),或对比率进行 Winsorize 截尾处理。

3.1.3 时间窗口特征

时间窗口特征通过滑动窗口在时间序列上计算统计量,捕捉风险随时间变化的趋势。在赔付率预测中,时间窗口特征能有效反映近期风险变化,比全量历史聚合更具时效性。

# Python 示例:滚动窗口特征构造
# 按保单生效日期排序,计算过去 90 天的滚动赔付率
policy_df = policy_df.sort_values('effective_date')

# 假设已有 daily_loss_rate 为每日赔付率
policy_df['rolling_90d_avg_loss'] = (
    policy_df['daily_loss_rate']
    .rolling(window=90, min_periods=30)
    .mean()
)

policy_df['rolling_90d_std_loss'] = (
    policy_df['daily_loss_rate']
    .rolling(window=90, min_periods=30)
    .std()
)

# 近期趋势:最近30天均值 vs 前90天均值
policy_df['recent_trend'] = (
    policy_df['daily_loss_rate'].rolling(30).mean() /
    policy_df['daily_loss_rate'].rolling(120).mean() - 1
)
特征构造方法全景图 聚合特征 比率特征 时间窗口特征 COUNT/SUM AVG/STD 赔付率 案均赔付 滚动均值 趋势变化 特征构造原则 1. 业务驱动:优先构造与赔付风险直接相关的业务比率(赔付率、案均赔付) 2. 时效优先:时间窗口特征应选择与预测周期匹配的窗口长度(如90天、180天) 3. 稳定性检查:构造后需检查特征缺失率、异常值分布,避免引入噪声 4. 可解释性:比率特征和聚合特征应能清晰解释其业务含义

3.2 特征选择方法

特征构造完成后,往往会产生大量候选特征。直接全部输入模型会导致维度灾难、过拟合和计算效率下降。特征选择的目标是从候选集中筛选出对预测目标最有区分能力的特征子集。

3.2.1 IV值(Information Value)

IV值(信息量)是精算和信用评分领域最常用的特征筛选指标,用于衡量特征对二元目标变量(如是否出险、是否赔付)的区分能力。IV值基于WOE(Weight of Evidence,证据权重)计算。

WOE计算公式:

WOE_i = ln( (Good_i / Good_total) / (Bad_i / Bad_total) )

IV计算公式:

IV = Σ ( (Good_i / Good_total) - (Bad_i / Bad_total) ) × WOE_i
IV值范围 预测能力 处理建议
< 0.02 无预测能力 建议删除
0.02 ~ 0.10 弱预测能力 可保留,但需谨慎
0.10 ~ 0.30 中等预测能力 推荐保留
0.30 ~ 0.50 强预测能力 优先保留
> 0.50 过强(可疑) 检查是否过拟合或数据泄露
# Python 示例:计算 IV 值
import numpy as np
import pandas as pd

def calc_iv(df, feature, target):
    """计算单个特征的 IV 值"""
    # 分箱处理(等频或等距)
    df['bin'] = pd.qcut(df[feature], q=10, duplicates='drop')
    
    grouped = df.groupby('bin')[target].agg(
        good='sum',
        total='count'
    ).reset_index()
    grouped['bad'] = grouped['total'] - grouped['good']
    
    good_total = grouped['good'].sum()
    bad_total = grouped['bad'].sum()
    
    grouped['good_pct'] = grouped['good'] / good_total
    grouped['bad_pct'] = grouped['bad'] / bad_total
    grouped['woe'] = np.log(grouped['good_pct'] / grouped['bad_pct'])
    grouped['iv_i'] = (grouped['good_pct'] - grouped['bad_pct']) * grouped['woe']
    
    iv = grouped['iv_i'].sum()
    return iv

# 计算所有特征的 IV 值
features = ['age', 'premium', 'vehicle_value', 'claim_history']
iv_scores = {feat: calc_iv(train_df, feat, 'is_claim') for feat in features}
print(pd.Series(iv_scores).sort_values(ascending=False))

3.2.2 相关性分析

相关性分析用于检测特征之间的线性或单调关系,避免多重共线性影响模型稳定性和可解释性。在精算模型中,高相关性特征会导致系数估计不稳定,降低模型泛化能力。

常用相关性指标:

  • Pearson相关系数:衡量线性相关性,适用于连续变量。
  • Spearman秩相关系数:衡量单调相关性,对异常值不敏感。
  • Kendall Tau:适用于小样本或存在大量并列等级的数据。
# Python 示例:相关性分析与特征筛选
import seaborn as sns
import matplotlib.pyplot as plt

# 计算相关性矩阵
corr_matrix = train_df[selected_features].corr(method='spearman')

# 找出高相关性特征对(阈值设为 0.7)
high_corr_pairs = []
for i in range(len(corr_matrix.columns)):
    for j in range(i+1, len(corr_matrix.columns)):
        if abs(corr_matrix.iloc[i, j]) > 0.7:
            high_corr_pairs.append((
                corr_matrix.columns[i],
                corr_matrix.columns[j],
                corr_matrix.iloc[i, j]
            ))

# 保留 IV 值更高的特征
features_to_drop = []
for feat1, feat2, corr_val in high_corr_pairs:
    if iv_scores[feat1] >= iv_scores[feat2]:
        features_to_drop.append(feat2)
    else:
        features_to_drop.append(feat1)

# 最终特征集
final_features = [f for f in selected_features if f not in features_to_drop]
特征选择流程:IV值 + 相关性分析 原始特征集 计算 IV 值 IV 值排序筛选 相关性分析 去冗余特征 最终特征集 迭代优化
常见陷阱: IV值过高(>0.5)的特征往往存在数据泄露风险,例如用未来的赔付信息预测当前风险。务必检查特征的时间顺序,确保特征构造时只使用历史数据。

3.3 特征工程最佳实践

结合精算业务特点,以下是在赔付率预测项目中经过验证的特征工程最佳实践:

  1. 分层构造:先构造基础聚合特征,再构造比率特征,最后构造时间窗口特征,形成层次化特征体系。
  2. 交叉验证:特征选择应在训练集内完成,避免使用测试集信息。建议使用时间序列交叉验证评估特征稳定性。
  3. 业务约束:保留至少2-3个业务核心特征(如历史赔付率、案均赔付),即使其IV值不高,以保证模型可解释性。
  4. 特征监控:上线后持续监控特征分布漂移(PSI),及时发现特征失效或数据质量问题。
效率建议: 在大型数据集上计算IV值和相关性时,建议先使用随机森林或LightGBM的特征重要性进行粗筛(保留Top 100-200特征),再使用IV值和相关性进行精筛,可大幅提升效率。