保险公司车险理赔欺诈检测(随机森林)

业务痛点:某财险公司年车险理赔额超80亿元,欺诈案件占比约8%(行业平均5-10%),年损失超6.4亿元。现有欺诈检测依赖人工审核(单案耗时2-3天),存在:

  • 漏检率高:人工审核后仍有30%欺诈案件未被识别
  • 成本高:专职审核团队50人,年人力成本超1200万元
  • 标准不一:不同审核员对"理赔合理性"判断差异大(如"单方事故无现场照片"的风险权重不一致)

算法团队:

  • 语言:Python 3.9、Scala 2.13(Spark开发)
  • 数据处理:Spark 3.4(分布式ETL)、Pandas 1.5(本地特征探索)
  • 特征存储:Feast 0.34(统一管理在线/离线特征)
  • 模型训练:Scikit-learn 1.2(随机森林)、XGBoost 2.0(备选)
  • 实验跟踪:MLflow 2.8(记录参数/指标/模型)、Weights & Biases(可视化)
  • 版本控制:Git(算法仓库:git@github.com:insurer/claims-fraud-algorithm.git)

业务团队:

  • 语言:Java 17(Spring Boot)、Go 1.20(高性能API)
  • 服务框架:FastAPI 0.104(Python轻量级API)、gRPC(跨语言通信)
  • 服务治理:Kong 3.4(API网关)、Consul 1.16(服务发现)
  • 监控:Prometheus 2.47(指标采集)、Grafana 10.2(可视化)
  • 版本控制:Git(业务仓库:git@github.com:insurer/claims-fraud-business.git)

数据准备与特征变化

(1)原数据结构(多源异构数据)

原始数据来自5个系统,存储在数据湖(HDFS)中,包含结构化(SQL表)、半结构化(JSON日志)、非结构化(事故照片元数据)数据。

① 理赔核心系统(claims_core,Hive表)

② 车辆管理系统(vehicle_info,MySQL表)

③ 投保人数据库(policyholders,PostgreSQL表)

④ 第三方数据(third_party,MongoDB集合)

json 复制代码
// 维修厂资质
{ "repair_shop_id": "RP045", "license_status": "有效", "fraud_history": 0, "avg_claim_amount": 7800 }
// 交警事故库
{ "accident_id": "ACC789", "claim_id": "CLM001", "is_false_report": 0, "weather": "晴" }

⑤ 反欺诈黑名单库(fraud_blacklist,HBase表)

(2)数据清洗与特征工程(算法团队负责)

缺失值处理:

  • has_witness(是否有证人):空值用"0"(无证人)填充(占80%);
  • last_maintenance_date(上次保养日期):空值用"事故前6个月"默认日期(基于车型平均保养周期)

异常值处理:

  • claim_amount(理赔金额):超过同车型历史95%分位数(如家用轿车>5万)视为异常,用"车型-损失类型"中位数替换
  • report_delay_hours(报案延迟小时数=report_time-accident_time):>72小时视为无效,标记为"高风险"并人工复核

特征提取(核心业务逻辑,从原始字段到特征字段)


特征编码与标准化

  • 类别特征:usage_type(车辆使用性质)、loss_type(损失类型)用Target Encoding(基于欺诈率编码,避免One-Hot维度爆炸)
  • 连续特征:amount_deviation_ratio、claim_freq_1y用RobustScaler(抗异常值)
  • 特征选择:用随机森林内置特征重要性(或SHAP值)筛选Top20特征(剔除重要性<0.01的特征)

特殊变化对比表(原数据->处理后特征)

(3)处理后特征矩阵示例(算法团队输出)


代码结构

算法团队仓库(claims-fraud-algorithm)

text 复制代码
claims-fraud-algorithm/
├── data_processing/          # 数据预处理(Spark/Scala)
│   ├── src/main/scala/com/insurer/
│   │   ├── DataCleaning.scala       # 缺失值/异常值处理
│   │   └── FeatureEngineering.scala  # 特征提取(含Target Encoding)
│   └── build.sbt                     # Scala依赖(Spark)
├── model_training/           # 模型训练(Python)
│   ├── train_random_forest.py       # 随机森林训练(含交叉验证)
│   ├── evaluate_model.py             # 评估指标(AUC/KS/混淆矩阵)
│   ├── feature_importance.py         # SHAP特征重要性分析
│   └── requirements.txt               # Python依赖
├── feature_store/             # 特征存储(Feast配置)
│   ├── feature_repo/
│   │   ├── features.py               # 特征定义(实体:claim_id)
│   │   └── feature_store.yaml         # Feast配置(在线/离线存储)
│   └── deploy_feature_store.sh       # 部署脚本(到K8s)
├── mlflow_tracking/           # MLflow实验跟踪
│   ├── run_experiment.py             # 启动实验并记录参数/指标
│   └── mlflow_server_config.yaml      # MLflow服务配置
└── README.md                         # 算法文档(特征字典/模型参数)
python 复制代码
import pandas as pd  
import numpy as np  
from sklearn.ensemble import RandomForestClassifier  
from sklearn.model_selection import StratifiedKFold, cross_val_score  
from sklearn.metrics import roc_auc_score, confusion_matrix  
import shap  
import mlflow  
import joblib  
from src.utils.logger import setup_logger  # 自定义日志工具  

logger = setup_logger(__name__)  

def load_processed_features(feature_path:str)->tuple:
	"""加载算法团队处理后的特征矩阵(含标签)"""
	df = pd.read_parquet(feature_path) # 特征矩阵
	X = df.drop(columns=["claim_id","is_fraud"])
	y = df["is_fraud"]  # 标签:1=欺诈,0=正常  
    return X, y 

def train_random_forest(X:pd.DataFrame,y:pd.Series,params:dict) -> RandomForestClassifier: 
	"""
	训练随机森林模型(带类别权重平衡)  
    Args:  
        X: 特征矩阵  
        y: 标签  
        params: 模型参数(n_estimators, max_depth等)  
    Returns:  
        训练好的随机森林模型  
	"""
	model = RandomForestClassifier(
		n_estimators=params["n_entimators"],# 树数量(默认100,调参后200)
		max_depth=params["max_depth"], # 树最大深度(防过拟合,调参后10)
		min_samples_split=params["min_samples_split"],# 分裂最小样本数(5)
		class_weight="balanced",# 自动平衡类别权重(欺诈样本少则权重高)
		random_state=42,
		n_jobs=-1 #并行训练(-1用所有CPU核心)
	)

	# 5折分层交叉验证(保持欺诈/正常样本比例)
	"""
	n_splits=5:将数据分成5份,进行5折交叉验证
	shuffle=True:拆分前先打乱数据顺序,防止原始数据顺序影响结果
	random_state=42:设置随机种子,确保结果可复现
	"""
	cv = StratifiedKFold(n_splits=5,shuffle=True,random_state=42)
	cv_scores = cross_val_score(model,X,y,cv=cv,scoring="roc_auc")# 将数据集分成5份,依次使用4份训练,1份测试 使用AUC-ROC作为评估指标
	logger.info(f"交叉验证AUC: {cv_scores.mean():.4f} ± {cv_scores.std():.4f}") 

	# 训练最终模型
	model.fit(X,y)

	# 记录实验
	with mlflow.start_run(run_name="random_forest_fraud_detection"):
		mlflow.log_params(params)
		mlflow.log_metric("cv_auc_mean", cv_scores.mean())  
        mlflow.log_metric("cv_auc_std", cv_scores.std())  
        mlflow.sklearn.log_model(model, "random_forest_model")  
        logger.info(f"模型训练完成,交叉验证AUC={cv_scores.mean():.4f}") 
	
	return model
		
def evaluate_model(model: RandomForestClassifier, X_test: pd.DataFrame, y_test: pd.Series)-> dict:  
	"""评估模型性能(AUC/KS/混淆矩阵)""" 
	y_pred_proba = model.predict_proba(X_test)[:, 1]  # 欺诈概率  
    y_pred = model.predict(X_test)  # 预测类别(阈值=0.5)

	# 核心指标
	auc = roc_auc_score(y_test,y_pred_proba)
	ks = calculate_ks(y_test, y_pred_proba) # 自定义KS值计算(见下方) 
	cm = confusion_matrix(y_test, y_pred) 
	tn, fp, fn, tp = cm.ravel()  
    precision = tp / (tp + fp) if (tp + fp) > 0 else 0  
    recall = tp / (tp + fn) if (tp + fn) > 0 else 0  

    metrics = {  
        "AUC-ROC": auc, "KS": ks, "Precision": precision, "Recall": recall,  
        "ConfusionMatrix": {"TN": int(tn), "FP": int(fp), "FN": int(fn), "TP": int(tp)}  
    }  
    logger.info(f"模型评估结果: {metrics}")  
    return metrics  

def calculate_ks(y_true:pd.Series,y_pred_proba:np.ndarray)->float:
	"""计算KS值(区分欺诈/正常样本的能力)""" 
	df = pd.DataFrame({"y_true":y_true,"y_pred_proba":y_pred_proba})
	df = df.sort_value("y_pred_proba",ascending=False).reset_index(drup=True)
	df["cum_good"] = (1 - df["y_true"]).cumsum() / (1 - df["y_true"]).sum()  # 累计正常样本占比  
    df["cum_bad"] = df["y_true"].cumsum() / df["y_true"].sum()  # 累计欺诈样本占比  
    df["ks"] = df["cum_bad"] - df["cum_good"]  # KS曲线差值  
    return df["ks"].max()  # KS值为最大差值

def analyze_feature_importance(model: RandomForestClassifier, X: pd.DataFrame)-> None:  
	"""用SHAP分析特征重要性(算法团队输出给业务团队解释用)""" 
	explainer = shap.TreeExplainer(model)
	shap_values = explainer.shap_values(X)
	shap.summary_plot(shap_values[1],X,plot_type="bar") # 欺诈类(label=1)的特征重要性 
	logger.info("SHAP特征重要性分析完成,图表保存至mlruns/shap_summary.png") 
	
if __name__ == "__main__":
	# 加载特征矩阵
	X,y = load_processed_features("data/processed/fraud_features.parquet")
	# 划分训练集/测试集(分层抽样)
	from sklearn.model_selection import train_test_split
	X_train,X_test,y_train,y_test = train_test_split(X,y,test_size=0.2,random_state=42, stratify=y)

	# 模型参数(经网格搜索调优)
	"""
	n_estimators,表示随机森林中决策树的数量,值越大,模型越稳定,泛化能力越好。但计算时间也会增加,200是一个平衡值
	max_depth,每个决策树的最大深度,控制树的复杂度。太深,容易过拟合;太浅,容易欠拟合
	min_samples_split,节点分裂所需的最小样本树,如果一个节点的样本树小于5,就不再分裂,防止模型对噪声数据过度学习

	实际会有多种组合,例如:
	{
	    'n_estimators': [100, 200, 300],
	    'max_depth': [5, 10, 15],
	    'min_samples_split': [2, 5, 10]
	}
	"""
	params = {"n_estimators": 200, "max_depth": 10, "min_samples_split": 5}

	# 训练模型
	model = train_random_forest(X_train,y_train,params)

	# 评估模型
	metrics = evaluate_model(model,X_test,y_test)

	# 保存模型(供业务团队调用)
	joblib.dump(model,"model/random_forest_fraud_model.pkl")

	# 特征重要性分析
	analyze_feature_importance(model,X_test)

模型文件:model/random_forest_fraud_model.pkl(训练好的随机森林模型)

特征服务:Feast特征存储配置(feature_store/feature_repo/)、特征字典(FEATURE_DICTIONARY.md)

实验报告:MLflow记录的模型参数(n_estimators=200, max_depth=10)、评估指标(AUC=0.93, KS=0.68, Precision=0.89, Recall=0.91)、SHAP特征重要性图表

dockerfile 复制代码
FROM python:3.9-slim  
WORKDIR /app  
COPY feature_store/feature_repo ./feature_repo  
COPY requirements.txt .  
RUN pip install --no-cache-dir -r requirements.txt  # 含feast==0.34  
EXPOSE 6566  # Feast gRPC端口  
CMD ["feast", "serve", "--port", "6566"]  # 启动特征服务

业务团队仓库(claims-fraud-business)

text 复制代码
claims-fraud-business/
├── api_gateway/               # API网关(Kong配置)
│   ├── kong.yml                      # 路由规则(转发至欺诈检测服务)
│   └── plugins/                       # 认证/限流插件
├── fraud_detection_service/   # 欺诈检测微服务(FastAPI)
│   ├── main.py                       # 服务入口(加载模型/特征客户端)
│   ├── predictor.py                  # 调用算法团队的模型和特征服务
│   ├── schemas.py                    # 请求/响应模型(Pydantic)
│   └── requirements.txt               # Python依赖(含grpcio)
├── monitoring/                # 监控配置
│   ├── prometheus_rules.yml           # 告警规则(如AUC<0.9触发告警)
│   └── grafana_dashboards/            # 可视化面板(API延迟/QPS)
├── deployment/                # 部署配置(K8s)
│   ├── fraud-detection-deployment.yaml # Deployment配置(副本数3)
│   └── service.yaml                   # Service配置(ClusterIP)
└── README.md                         # 业务文档(API调用示例)
python 复制代码
import grpc
import joblib
import pandas as pd
from concurrent import futures
from feast import FeatureStore # 调用算法团队的特征服务
from src.schemas import ClaimRequest,FraudPredictionResponse # Pydantic模型(请求/响应)  
from src.utils.logger import setup_logger

logger = setup_logger(__name__)  

class FraudPredictor:
	def __init__(self,model_path:str,feature_store_config:str):
		"""初始化预测器:加载算法团队的模型和特征服务客户端"""	
		self.model = joblib.load(model_path) #加载随机森林模型
		self.feature_store = FeatureStore(repo_path=feature_store_config)  # 连接Feast特征存储  
        logger.info("欺诈预测器初始化完成:模型加载成功,特征服务连接成功")  

	def get_online_features(self, claim_id: str) -> pd.DataFrame:
		"""调用算法团队的特征服务,获取实时特征(在线特征)"""
		# 定义特征视图(与算法团队的Feast配置一致)  
        feature_refs = [  
            "has_fraud_history", "claim_freq_1y", "amount_deviation_ratio",  
            "report_delay_bin", "vehicle_risk_score", "shop_fraud_history"  
        ]  
        # 从Feast获取实时特征(实体:claim_id)  
        feature_vector = self.feature_store.get_online_features(  
            entity_rows=[{"claim_id": claim_id}],  
            features=feature_refs  
        ).to_dict()  
        return pd.DataFrame(feature_vector)

	def predict(self, claim_request: ClaimRequest) -> FraudPredictionResponse: 
		"""核心预测逻辑:融合请求参数与特征服务数据,调用模型预测""" 
		try:  
            # 1. 从请求中获取claim_id(业务系统传入的唯一标识)  
            claim_id = claim_request.claim_id  

            # 2. 调用特征服务获取实时特征(算法团队维护)  
            online_features = self.get_online_features(claim_id)  
            if online_features.empty:  
                raise ValueError(f"特征服务未找到claim_id={claim_id}的特征")  

            # 3. 融合请求参数中的非特征字段(如accident_time_risk需实时计算)  
            # (注:部分特征需业务系统实时计算,如夜间出险标记)  
            accident_hour = pd.to_datetime(claim_request.accident_time).hour  
            accident_time_risk = 1 if (22 <= accident_hour or accident_hour < 6) else 0  

            # 4. 构造模型输入特征向量(与算法团队训练时一致)  
            feature_vector = online_features.copy()  
            feature_vector["accident_time_risk"] = accident_time_risk  # 补充实时特征  
            feature_vector = feature_vector[self.model.feature_names_in_]  # 按模型训练时的特征顺序排列  

            # 5. 调用随机森林模型预测欺诈概率  
            fraud_prob = self.model.predict_proba(feature_vector)[0][1]  # 欺诈类概率(label=1)  
            risk_level = "高风险" if fraud_prob > 0.7 else "中风险" if fraud_prob > 0.4 else "低风险"  

            # 6. 构造响应(含解释性信息,基于算法团队的SHAP结果)  
            response = FraudPredictionResponse(  
                claim_id=claim_id,  
                fraud_probability=round(fraud_prob, 4),  
                risk_level=risk_level,  
                key_factors=[  # 基于算法团队的SHAP特征重要性(示例)  
                    {"factor": "历史欺诈标记", "impact": "正向影响", "shap_value": 0.32},  
                    {"factor": "理赔金额偏离度", "impact": "正向影响", "shap_value": 0.28},  
                    {"factor": "维修厂欺诈历史", "impact": "正向影响", "shap_value": 0.25}  
                ],  
                timestamp=pd.Timestamp.now().isoformat()  
            )  
            logger.info(f"预测完成:claim_id={claim_id}, 欺诈概率={fraud_prob:.4f}")  
            return response  

        except Exception as e:  
            logger.error(f"预测失败:claim_id={claim_request.claim_id}, 错误={str(e)}", exc_info=True)  
            raise
	
dockerfile 复制代码
FROM python:3.9-slim  
WORKDIR /app  
COPY fraud_detection_service/ ./  
COPY model/random_forest_fraud_model.pkl ./model/  
COPY requirements.txt .  
RUN pip install --no-cache-dir -r requirements.txt  # 含fastapi, uvicorn, feast  
EXPOSE 8000  
CMD ["uvicorn", "main:app", "--host", "0.0.0.0", "--port", "8000", "--workers", "4"]  # 4个工作进程
yml 复制代码
# deployment.yaml  
apiVersion: apps/v1  
kind: Deployment  
metadata:  
  name: fraud-detection-service  
spec:  
  replicas: 3  # 3副本负载均衡  
  selector:  
    matchLabels:  
      app: fraud-detection  
  template:  
    metadata:  
      labels:  
        app: fraud-detection  
    spec:  
      containers:  
      - name: fraud-detection  
        image: insurer/fraud-detection-service:v1.0  # 业务团队镜像  
        ports:  
        - containerPort: 8000  
        resources:  
          limits:  
            cpu: "2"  
            memory: "4Gi"  
          requests:  
            cpu: "1"  
            memory: "2Gi"  
        livenessProbe:  # 健康检查  
          httpGet:  
            path: /health  
            port: 8000  
          initialDelaySeconds: 30  
          periodSeconds: 10  
---  
apiVersion: v1  
kind: Service  
metadata:  
  name: fraud-detection-service  
spec:  
  selector:  
    app: fraud-detection  
  ports:  
  - port: 80  
    targetPort: 8000  
  type: ClusterIP

应用

①、实时欺诈检测(理赔申请提交时触发)

理赔审核系统调用业务团队的API网关(https://api.insurer.com/fraud/predict),传入理赔申请信息(claim_id、accident_time、claim_amount等)

bash 复制代码
curl -X POST https://api.insurer.com/fraud/predict \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer <TOKEN>" \  # 认证令牌  
  -d '{
    "claim_id": "CLM003",
    "accident_time": "2023-07-15T23:30:00",  # 夜间出险(实时特征)
    "claim_amount": 15000,
    "policy_id": "POL789",
    "vehicle_id": "VH202"
  }'

②、分级处置决策

API返回欺诈概率(如0.82)和风险等级(高风险),理赔系统按规则决策:

  • 自动拒赔:欺诈概率>0.7(高风险),触发自动拒赔并标记欺诈嫌疑
  • 人工复核:0.4<欺诈概率≤0.7(中风险),分配至资深审核员重点核查(如维修厂资质、事故照片真实性)
  • 自动通过:欺诈概率≤0.4(低风险),进入正常赔付流程

③、监控与迭代

实时监控:Prometheus采集API响应时间、QPS、错误率,Grafana展示;监控模型预测分布(PSI指标),若PSI>0.25(特征分布漂移)触发告警

模型迭代:算法团队每月用新数据增量训练,每季度全量重训;若AUC连续2周<0.9,自动触发重训流程(Airflow调度)

业务反馈闭环:风控团队每周分析误判案例(如"真实欺诈但被误判为正常"),反馈至算法团队优化特征(如增加"报案人与被保险人关系"特征)

相关推荐
大江东去浪淘尽千古风流人物6 小时前
【VLN】VLN(Vision-and-Language Navigation视觉语言导航)算法本质,范式难点及解决方向(1)
人工智能·python·算法
努力学算法的蒟蒻7 小时前
day79(2.7)——leetcode面试经典150
算法·leetcode·职场和发展
2401_841495647 小时前
【LeetCode刷题】二叉树的层序遍历
数据结构·python·算法·leetcode·二叉树··队列
AC赳赳老秦7 小时前
2026国产算力新周期:DeepSeek实战适配英伟达H200,引领大模型训练效率跃升
大数据·前端·人工智能·算法·tidb·memcache·deepseek
2401_841495648 小时前
【LeetCode刷题】二叉树的直径
数据结构·python·算法·leetcode·二叉树··递归
budingxiaomoli8 小时前
优选算法-字符串
算法
qq7422349848 小时前
APS系统与OR-Tools完全指南:智能排产与优化算法实战解析
人工智能·算法·工业·aps·排程
A尘埃8 小时前
超市购物篮关联分析与货架优化(Apriori算法)
算法
.小墨迹9 小时前
apollo学习之借道超车的速度规划
linux·c++·学习·算法·ubuntu