理赔预测:使用 AI 预估赔付金额与欺诈风险

FreeGuideOnline 最新 2026-06-23

python import pandas as pd import numpy as np from sklearn.model_selection import train_test_split, cross_val_score from sklearn.preprocessing import OneHotEncoder, StandardScaler from sklearn.compose import ColumnTransformer from sklearn.pipeline import Pipeline from sklearn.ensemble import RandomForestRegressor, RandomForestClassifier from sklearn.metrics import mean_absolute_error, classification_report, roc_auc_score


### 生成模拟数据集

为方便练习,我们创建一个包含 5000 条记录的模拟数据集。真实数据请从 Kaggle 或保险公司内部获取。

```python
np.random.seed(42)
n = 5000
data = pd.DataFrame({
    'accident_type': np.random.choice(['Collision','Theft','Fire','Vandalism'], n, p=[0.6,0.2,0.15,0.05]),
    'injury_severity': np.random.choice(['None','Moderate','Severe'], n, p=[0.5,0.3,0.2]),
    'policy_age': np.random.randint(0, 10, n),
    'vehicle_value': np.random.normal(20000, 8000, n).clip(5000, 100000),
    'driver_age': np.random.randint(18, 80, n),
    'witness_ind': np.random.choice([0,1], n, p=[0.7,0.3]),  # 是否有目击者
    'police_report': np.random.choice([0,1], n, p=[0.4,0.6])   # 是否涉及警方报告
})
data['vehicle_value'] = data['vehicle_value'].astype(int)

接下来生成目标变量,使赔付金额与特征产生合理关系,并注入少量欺诈案例。

# 赔付金额基础公式 + 噪声
data['claim_amount'] = (
    5000 +
    (data['vehicle_value'] * 0.3) +
    (data['injury_severity'].map({'None':0, 'Moderate':5000, 'Severe':12000})) +
    (data['accident_type'].map({'Collision':2000, 'Theft':4000, 'Fire':6000, 'Vandalism':1500})) -
    (data['policy_age'] * 200) +
    np.random.normal(0, 3000, n)
).clip(0, 50000).astype(int)

# 欺诈标签:设置一些异常高额+无目击者+无警方报告的组合为欺诈
fraud_score = (
    (data['claim_amount'] > 20000).astype(int) * 2 +
    (data['witness_ind'] == 0).astype(int) * 1.5 +
    (data['police_report'] == 0).astype(int) * 1
)
threshold = fraud_score.quantile(0.93)
data['is_fraud'] = (fraud_score >= threshold).astype(int)

print(f"欺诈占比: {data['is_fraud'].mean():.2%}")

构建赔付金额预测模型

特征工程与预处理管道

我们将分类变量进行独热编码,数值变量标准化。注意:对于赔付金额预测,我们不会使用is_fraud作为特征。

X = data.drop(['claim_amount', 'is_fraud'], axis=1)
y_amount = data['claim_amount']

categorical_cols = ['accident_type', 'injury_severity']
numerical_cols = ['policy_age', 'vehicle_value', 'driver_age', 'witness_ind', 'police_report']

preprocessor = ColumnTransformer([
    ('cat', OneHotEncoder(handle_unknown='ignore'), categorical_cols),
    ('num', StandardScaler(), numerical_cols)
])

训练回归模型

使用随机森林作为基线,因为其能较好地处理非线性关系且不易过拟合。

X_train, X_test, y_train, y_test = train_test_split(X, y_amount, test_size=0.2, random_state=42)

rf_reg = Pipeline([
    ('prep', preprocessor),
    ('reg', RandomForestRegressor(n_estimators=100, random_state=42))
])
rf_reg.fit(X_train, y_train)

y_pred = rf_reg.predict(X_test)
mae = mean_absolute_error(y_test, y_pred)
print(f"赔付金额预测 MAE: {mae:.2f}")

模型评估与解读

  • 平均绝对误差(MAE):直接反映预测金额与实际金额的平均偏差。
  • 可进一步分析残差分布,查看是否在高额案件上系统性地低估。
  • 若业务更关注大额赔付的准确性,可考虑使用带权重的损失函数或采用对数转换。

概率性预测的价值

除点估计外,可输出预测区间。例如使用分位数回归或随机森林自带的树方差估算不确定性,帮助精算团队设置准备金范围。本教程暂不展开,但值得在实际项目中探索。

构建欺诈风险预测模型

处理极度不均衡类别

欺诈占比通常只有 1%–5%,直接训练分类器会倾向于预测所有案件为非欺诈,准确率高但毫无意义。需要采用综合策略:

  1. 重采样:对少数类过采样(SMOTE)或对多数类欠采样。
  2. 调整类别权重:在模型参数中设置 class_weight='balanced'
  3. 评估指标:绝不用准确率,而关注召回率(抓出多少欺诈)、精确率、AUC 等。

训练欺诈检测模型

y_fraud = data['is_fraud']

X_train_f, X_test_f, y_train_f, y_test_f = train_test_split(
    X, y_fraud, test_size=0.2, random_state=42, stratify=y_fraud
)

rf_clf = Pipeline([
    ('prep', preprocessor),
    ('clf', RandomForestClassifier(n_estimators=100, class_weight='balanced', random_state=42))
])
rf_clf.fit(X_train_f, y_train_f)

y_prob = rf_clf.predict_proba(X_test_f)[:, 1]

评估欺诈模型

# 设置阈值,例如 0.3 以提高召回率
threshold = 0.3
y_pred_label = (y_prob >= threshold).astype(int)

print(classification_report(y_test_f, y_pred_label, target_names=['非欺诈','欺诈']))
print(f"AUC: {roc_auc_score(y_test_f, y_prob):.4f}")

校准与业务阈值

  • 概率校准对成本敏感场景很关键。若每笔欺诈案平均挽回 $8000,而调查一笔非欺诈案的成本为 $50,可通过成本矩阵找到最优阈值。
  • 输出概率分数,便于调查团队按风险优先级排序。

双重预测的统一工作流

在实际系统中,新提交的理赔将同时经过两个模型:

  1. 赔付金额模型给出预估金额,用于资金准备和快速赔付。
  2. 欺诈模型给出风险分数,高于阈值的案件自动转入人工调查。

操作示例

new_claim = pd.DataFrame({
    'accident_type': ['Collision'],
    'injury_severity': ['Moderate'],
    'policy_age': [3],
    'vehicle_value': [25000],
    'driver_age': [35],
    'witness_ind': [1],
    'police_report': [1]
})

pred_amount = rf_reg.predict(new_claim)[0]
pred_fraud_prob = rf_clf.predict_proba(new_claim)[0, 1]

print(f"预估赔付: ${pred_amount:.2f}")
print(f"欺诈概率: {pred_fraud_prob:.2%}")

特征重要性分析与解释

两个模型可分别查看特征重要性,理解驱动预测的关键因素。

import matplotlib.pyplot as plt

def plot_feature_importance(model, feature_names, title):
    importances = model.named_steps['clf' if 'clf' in model.named_steps else 'reg'].feature_importances_
    indices = np.argsort(importances)[::-1]
    plt.figure(figsize=(10,5))
    plt.title(title)
    plt.bar(range(len(importances)), importances[indices], align='center')
    plt.xticks(range(len(importances)), [feature_names[i] for i in indices], rotation=45)
    plt.tight_layout()

# 获取预处理后的特征名
prep = rf_reg.named_steps['prep']
cat_features = prep.named_transformers_['cat'].get_feature_names_out(categorical_cols)
all_features = list(cat_features) + numerical_cols

plot_feature_importance(rf_reg, all_features, "赔付金额特征重要性")
plot_feature_importance(rf_clf, all_features, "欺诈检测特征重要性")