4. 不平衡数据处理:精算数据中欺诈/赔付样本的稀疏性、SMOTE过采样与代价敏感学习、XGBoost的scale_pos_weight参数
在精算建模中,欺诈检测与赔付预测面临一个核心挑战:正样本(欺诈/赔付)极度稀疏。通常,欺诈案件占比不足总交易量的1%,赔付案件在健康险或车险中往往也低于5%。直接使用原始不平衡数据训练XGBoost,模型会倾向于预测多数类(正常样本),导致召回率极低,无法有效拦截风险。
本章将系统讲解三种应对策略:数据层面的SMOTE过采样、算法层面的代价敏感学习,以及XGBoost内置的scale_pos_weight参数,并给出精算场景下的实战选择建议。
4.1 精算数据中的稀疏性特征
精算数据的不平衡性具有以下典型特征:
| 业务场景 | 正样本比例 | 稀疏性影响 |
|---|---|---|
| 车险欺诈检测 | 0.5% – 2% | 模型几乎全判为正常,欺诈召回率趋近于0 |
| 健康险异常赔付 | 1% – 5% | 高赔付样本被淹没,模型低估风险 |
| 寿险早期退保 | 3% – 8% | 退保预测概率校准偏差严重 |
| 财产险大额索赔 | < 0.1% | 极端稀疏,传统过采样可能引入噪声 |
4.2 SMOTE过采样:合成少数类样本
SMOTE(Synthetic Minority Over-sampling Technique)通过在少数类样本之间插值生成新样本,而非简单复制,从而缓解过拟合风险。
4.2.1 SMOTE算法流程
- 选择种子样本:从少数类中随机选取一个样本点A。
- 寻找近邻:在A的k个最近邻(通常k=5)中随机选择一个少数类样本B。
- 线性插值:在A与B的连线上随机生成一个新样本点C = A + λ × (B - A),其中λ ∈ [0, 1]。
- 重复:直到少数类样本数量达到目标比例(如与多数类1:1)。
4.2.2 SMOTE在Python中的实现
from imblearn.over_sampling import SMOTE
from sklearn.model_selection import train_test_split
# 假设X为特征矩阵,y为标签(0:正常,1:欺诈/赔付)
X_train, X_test, y_train, y_test = train_test_split(
X, y, test_size=0.3, random_state=42, stratify=y
)
# 应用SMOTE,目标使正负样本比例达到1:1
smote = SMOTE(sampling_strategy=1.0, random_state=42, k_neighbors=5)
X_train_resampled, y_train_resampled = smote.fit_resample(X_train, y_train)
print(f"原始训练集正样本数: {sum(y_train)}")
print(f"SMOTE后训练集正样本数: {sum(y_train_resampled)}")
4.3 代价敏感学习:为误分类赋予不同代价
代价敏感学习不改变数据分布,而是在损失函数中为不同类别的误分类赋予不同权重。对于精算欺诈检测,将正常样本误判为欺诈(假阳性)的成本较低,但将欺诈样本误判为正常(假阴性)的成本极高。
4.3.1 代价矩阵设计
| 实际 \ 预测 | 预测为正常 | 预测为欺诈/赔付 |
|---|---|---|
| 实际正常 | 0(正确) | CFP(误拦截成本) |
| 实际欺诈/赔付 | CFN(漏过成本) | 0(正确) |
在精算场景中,通常设置 CFN = 10 × CFP 甚至更高,具体取决于欺诈案均损失与正常客户投诉成本之比。
4.3.2 XGBoost中的代价敏感实现
XGBoost原生支持通过sample_weight参数为每个样本赋予权重,从而实现代价敏感学习:
import xgboost as xgb
# 计算样本权重:正样本权重 = 负样本数 / 正样本数
weight_ratio = len(y_train[y_train == 0]) / len(y_train[y_train == 1])
sample_weights = np.where(y_train == 1, weight_ratio, 1.0)
model = xgb.XGBClassifier(
n_estimators=200,
max_depth=6,
learning_rate=0.1,
random_state=42
)
model.fit(X_train, y_train, sample_weight=sample_weights)
4.4 XGBoost的scale_pos_weight参数
scale_pos_weight是XGBoost专门为二分类不平衡问题设计的参数,其本质是一种自动化的代价敏感机制。该参数控制正负样本的权重比例,直接影响损失函数中正样本的梯度贡献。
4.4.1 参数原理
scale_pos_weight的推荐计算公式为:
scale_pos_weight = 负样本数量 / 正样本数量
XGBoost内部会将该权重应用于正样本的损失函数梯度,使得模型在训练时更加关注少数类。与手动设置sample_weight相比,scale_pos_weight更简洁且经过XGBoost底层优化。
4.4.2 实战代码示例
import xgboost as xgb
# 计算scale_pos_weight
neg_count = sum(y_train == 0)
pos_count = sum(y_train == 1)
scale_weight = neg_count / pos_count
model = xgb.XGBClassifier(
n_estimators=200,
max_depth=6,
learning_rate=0.1,
scale_pos_weight=scale_weight,
random_state=42
)
model.fit(X_train, y_train)
# 预测概率用于风险评分
y_pred_proba = model.predict_proba(X_test)[:, 1]
4.4.3 参数调优建议
| 场景 | scale_pos_weight设置 | 说明 |
|---|---|---|
| 标准不平衡(1:10 ~ 1:50) | neg_count / pos_count | 直接使用公式计算,效果稳定 |
| 极端不平衡(> 1:100) | 公式值 × 0.5 ~ 0.8 | 降低权重防止过拟合噪声 |
| 高假阳性成本场景 | 公式值 × 1.2 ~ 1.5 | 进一步强化对正样本的识别 |
| 与SMOTE联合使用 | 公式值 × 0.3 ~ 0.5 | 数据已过采样,降低额外权重 |
4.5 三种策略对比与选择
| 策略 | 核心思想 | 优点 | 缺点 | 精算适用性 |
|---|---|---|---|---|
| SMOTE过采样 | 合成少数类样本 | 增加正样本多样性,提升召回 | 可能引入噪声,离散特征效果差 | 正样本≥1000且特征连续时优先 |
| 代价敏感学习 | 调整样本权重 | 灵活控制误分类代价,不改变数据 | 权重设置依赖业务经验 | 适用于所有场景,需业务方参与定权 |
| scale_pos_weight | XGBoost内置权重 | 简洁高效,无需额外库 | 仅适用于XGBoost,灵活性有限 | 精算建模首选,快速验证基线 |
4.6 不平衡处理策略决策流程
下图展示了精算建模中不平衡数据处理的完整决策路径:
4.7 实战案例:车险欺诈实时评分中的不平衡处理
某车险公司构建实时欺诈评分模型,历史数据中欺诈样本占比0.8%。采用以下策略组合:
- 基线模型:直接使用scale_pos_weight = 124(负样本数/正样本数),召回率仅32%。
- 优化1:将scale_pos_weight调整为80(降低权重防止过拟合),召回率提升至45%。
- 优化2:叠加代价敏感学习,正样本权重设为15,召回率提升至58%。
- 优化3:在正样本达到2000条后引入SMOTE,最终召回率达到71%,假阳性率控制在3%以内。
4.8 本章小结
- 精算数据中欺诈/赔付样本的稀疏性是建模的核心挑战,正样本比例通常低于5%。
- SMOTE过采样通过合成样本提升正样本数量,但需注意离散特征和噪声问题。
- 代价敏感学习通过调整样本权重灵活控制误分类代价,适用于所有精算场景。
- XGBoost的
scale_pos_weight参数是最简洁的不平衡处理方式,推荐作为基线首选。 - 实战中建议采用“scale_pos_weight → 代价敏感学习 → SMOTE”的渐进式优化路径。