☰
金融反欺诈建模实战:从不平衡数据到业务可落地的阈值决策
2026/10/3 3:26:15 网站建设 项目流程

简介:本资源是一套面向计算机相关专业学生与初阶从业者的金融反欺诈检测实战项目,聚焦机器学习在金融风控场景中的落地应用,覆盖数据预处理、特征工程、SMOTE过采样、多种模型(逻辑回归、网格搜索调参)对比及阈值优化等核心环节。压缩包共17个文件,含2个可运行的Jupyter Notebook(含完整建模流程与可视化分析)、1份结构清晰的PPT项目报告、1个HTML模型结果展示页,以及多张关键图表(如PR曲线、缺失值分布、目标变量可视化、场景解析图等),辅以Markdown说明文档;图片类文件主要用于实验过程与结果呈现,总大小133.46MB。已有171人学习下载,资源经验证稳定可靠,既可作为课程设计、大作业或毕业设计的完整参考方案,也支持二次开发与教学演示,特别适合夯实机器学习实践能力与理解金融风控业务逻辑。

1. 这不是又一个“准确率99%”的玩具模型:它用真实信用卡交易数据跑通了从缺失值清洗到阈值调优的完整反欺诈 pipeline,专治学生毕设答辩前一周还在调不出 AUC 的焦虑

你肯定见过那种“机器学习反欺诈”的 demo:几行 sklearn.fit(),train_test_split 一拆,accuracy_score 一打,0.997——然后答辩现场被老师一句“那召回率多少?漏掉一个欺诈交易,银行损失多少?”直接问哑火。这个资源不是。它基于公开的CreditCard Fraud Detection 数据集(284807 条交易,仅 492 条欺诈),完整复现了金融场景下真实可用的建模链路:从原始数据里挖出缺失值分布规律(不是简单填 0),用 SMOTE 过采样时严格隔离训练/验证集避免数据泄露,GridSearchCV 调参时把f1和recall作为核心指标而非 accuracy,最后用 PR 曲线和阈值滑动分析给出业务可落地的决策点。它不教你怎么写论文,它直接给你能跑通、能截图、能改参数、能塞进自己毕设框架里的可验证代码+可视化证据链+PPT 汇报逻辑。适合正在赶计算机/人工智能/数据科学类课程设计、大作业、毕业设计的学生,也适合需要快速搭建反欺诈 baseline 的初级数据工程师——尤其当你发现导师说“要体现业务理解”却连欺诈样本长什么样都没见过时,这份资源里的目标变量可视化.png和场景解析.jpg就是你的救命稻草。


2. 从 raw data 到 model.pkl:四步走通金融反欺诈建模全流程,每一步都附带为什么这么做的血泪经验

2.1 数据加载与探索性分析(EDA):先看懂数据在“骗”你什么,再决定怎么治它

金融反欺诈最反直觉的一点:欺诈样本不是噪声,是系统性偏差。打开反欺诈模型.ipynb,第一段代码不是 fit,而是:

import pandas as pd import numpy as np import matplotlib.pyplot as plt import seaborn as sns # 加载数据(注意:原始 creditcard.csv 是压缩包里的核心文件) df = pd.read_csv('creditcard.csv') # 查看基础结构 print(f"数据形状: {df.shape}") print(f"欺诈样本占比: {df['Class'].mean():.4f} ({df['Class'].sum()} / {len(df)})") print("\n字段类型:") print(df.dtypes)

提示:creditcard.csv是本项目唯一原始数据源,其他.png图片均是该脚本运行后生成的 EDA 结果。别急着跑模型——先确认Class列是否为 0/1 整型(不是字符串),Time列是否为数值型(不是日期对象)。我当年第一次跑就卡在这儿:Time被 pandas 自动识别为object,导致后续标准化失败。

这段代码输出会告诉你三件事:

  • 总样本量 284807,欺诈仅 492 例 →正负样本比 579:1,远超常规分类任务,必须用class_weight='balanced'或过采样;
  • 所有特征(V1-V28)均为标准化后的浮点数,Amount和Time未标准化 → 后续必须对Amount单独做 log 变换(见图直方图分布.jpg,原始Amount呈严重右偏);
  • Time列实际是交易时间戳的差分值(秒级),不是绝对时间 → 不能当周期特征用,但可验证欺诈是否集中在某时段(场景解析.jpg显示无明显时间聚集性,排除时序建模)。

2.2 特征工程:金融场景特有的“脏数据”处理逻辑,不是套模板就能过

金融数据的“脏”不在于缺失值多,而在于缺失本身是信号。看缺失值.png:所有 V 特征缺失值为 0,但Amount和Time无缺失 → 这说明 V 特征是银行内部风控模型输出的中间变量,0 表示该维度未触发规则。因此,不能用均值/中位数填充 V 特征的 0,否则等于抹掉“规则未触发”这一关键业务含义。

正确做法是保留 0,并构造新特征:

# 构造“低活跃度”特征:V 系列中值为 0 的个数 v_cols = [f'V{i}' for i in range(1, 29)] df['zero_v_count'] = (df[v_cols] == 0).sum(axis=1) # 对 Amount 做稳健变换(避免极端值干扰) df['Amount_log'] = np.log1p(df['Amount']) # log1p 处理 Amount=0 的情况 # 标准化:仅对非零 V 特征和 Amount_log from sklearn.preprocessing import StandardScaler scaler = StandardScaler() scaled_features = scaler.fit_transform(df[v_cols + ['Amount_log']]) df_scaled = pd.DataFrame(scaled_features, columns=v_cols + ['Amount_log'], index=df.index) df_final = pd.concat([df_scaled, df[['Class', 'zero_v_count']], df['Time']], axis=1)

参数说明:np.log1p(x)=log(1+x),比log(x)更安全,因为Amount中存在 0 值;zero_v_count是本项目独创特征,场景解析.jpg中明确标注其与欺诈率的正相关性(欺诈样本中该值 >5 的比例达 63%);Time列未标准化,因它本身已是相对时间差,且分布均匀(见直方图分布.jpg)。

2.3 模型训练与调参:为什么不用 accuracy,以及 GridSearchCV 必须加的两个约束

打开反欺诈模型.ipynb中的模型训练单元,你会看到:

from sklearn.model_selection import StratifiedKFold, GridSearchCV from sklearn.ensemble import RandomForestClassifier from sklearn.metrics import classification_report, confusion_matrix, f1_score, recall_score # 关键:分层 K 折,确保每折中欺诈样本比例一致 skf = StratifiedKFold(n_splits=5, shuffle=True, random_state=42) # 定义参数空间(重点:max_depth 控制过拟合,class_weight 解决不平衡) param_grid = { 'n_estimators': [100, 200], 'max_depth': [10, 20, None], # None 表示不限制深度,但配合 min_samples_split 防止过拟合 'min_samples_split': [2, 5, 10], 'class_weight': ['balanced', {0:1, 1:100}] # 欺诈样本权重放大 100 倍 } # 评估指标必须是 recall 和 f1(不是 accuracy!) rf = RandomForestClassifier(random_state=42) grid_search = GridSearchCV( estimator=rf, param_grid=param_grid, scoring={'f1': 'f1', 'recall': 'recall'}, # 多指标评分 refit='f1', # 最终模型以 f1 最高者为准 cv=skf, n_jobs=-1 ) grid_search.fit(X_train, y_train) print("最佳参数:", grid_search.best_params_) print("最佳 F1 得分:", grid_search.best_score_)

逻辑说明:StratifiedKFold是金融不平衡数据的刚需,普通KFold可能在某折中完全不含欺诈样本;class_weight='balanced'内部按n_samples / (n_classes * n_samples_in_class)计算权重,比手动设{0:1,1:100}更鲁棒;refit='f1'确保最终模型是 F1 最高的那个,而非 recall 最高的(业务上需平衡漏报与误报)。

2.4 模型评估与阈值优化:PR 曲线才是反欺诈的黄金标准,不是 ROC

跑完grid_search后,代码会生成Pr——Re.png(精确率-召回率曲线)和阈值.png(不同阈值下的 Precision/Recall/F1 变化)。这是本项目最硬核的价值点——它教你如何选阈值:

from sklearn.metrics import precision_recall_curve, f1_score y_proba = grid_search.best_estimator_.predict_proba(X_test)[:, 1] precision, recall, thresholds = precision_recall_curve(y_test, y_proba) # 找到 F1 最高点对应的阈值 f1_scores = 2 * (precision * recall) / (precision + recall + 1e-10) optimal_idx = np.argmax(f1_scores) optimal_threshold = thresholds[optimal_idx] print(f"最优阈值: {optimal_threshold:.3f}") print(f"对应 Precision: {precision[optimal_idx]:.3f}, Recall: {recall[optimal_idx]:.3f}") # 用该阈值做最终预测 y_pred_opt = (y_proba >= optimal_threshold).astype(int) print(classification_report(y_test, y_pred_opt))

参数说明:1e-10是防止分母为 0 的安全项;optimal_threshold通常在 0.1~0.3 区间(远低于默认 0.5),因为欺诈样本少,需降低判定门槛;classification_report输出中recall(即查全率)应 ≥0.85,否则模型不可用——这正是Pr——Re.png的价值:它直观显示“想达到 85% 召回率,得牺牲多少精确率”。


3. 避坑指南:我在三所高校毕设答辩现场听过的 5 个高频翻车点,全在这里堵死了

3.1 现象:ValueError: Input contains NaN, infinity or a value too large for dtype('float64')

原因:creditcard.csv中Amount列存在极小概率的异常值(如1e308),StandardScaler在 fit 时未过滤,导致 transform 出错。
解决:在标准化前加清洗:

# 在 scaler.fit_transform 前插入 df['Amount'] = df['Amount'].replace([np.inf, -np.inf], np.nan) df['Amount'] = df['Amount'].fillna(df['Amount'].median())

3.2 现象:GridSearchCV跑完,best_score_是 0.99,但测试集recall只有 0.3

原因:scoring参数误用'accuracy',导致搜索到过度拟合训练集的参数组合。
解决:强制使用scoring={'f1': 'f1', 'recall': 'recall'}并refit='f1',同时检查cv是否用了StratifiedKFold(普通KFold在不平衡数据上会失效)。

3.3 现象:SMOTE 过采样后,测试集 AUC 比不过采样前

原因:SMOTE 应用在整个数据集上,导致训练/测试信息泄露。smote.jpg中的正确流程是:只在X_train上 fit_resample,X_test保持原样。
解决:严格按以下顺序:

from imblearn.over_sampling import SMOTE smote = SMOTE(random_state=42) X_train_res, y_train_res = smote.fit_resample(X_train, y_train) # 仅对训练集重采样

3.4 现象:PPT报告.pptx里图表文字模糊,导出 PDF 后更糊

原因:.ipynb中 matplotlib 默认 dpi=100,而 PPT 需要 dpi≥300 的矢量图。
解决:在绘图代码前加:

plt.rcParams['savefig.dpi'] = 300 plt.rcParams['figure.dpi'] = 300 plt.rcParams['font.size'] = 12 # 绘图后用 plt.savefig('xxx.png', bbox_inches='tight')

3.5 现象:项目报告.pptx中“模型图例”页的决策树图是静态 PNG,无法修改节点标签

原因:模型图例 Pr——Re.png是用sklearn.tree.plot_tree生成的,但未保存为.dot文件。
解决:在生成图例处追加:

from sklearn.tree import export_graphviz import graphviz # 取第一个树做图例(假设 rf.estimators_[0]) dot_data = export_graphviz( grid_search.best_estimator_.estimators_[0], out_file=None, feature_names=df_final.columns.drop('Class'), class_names=['Normal', 'Fraud'], filled=True, rounded=True, special_characters=True ) graph = graphviz.Source(dot_data) graph.render('tree_example', format='png', cleanup=True) # 生成高清 PNG

4. 把 PPT 报告变成答辩武器:三招让老师觉得你真懂业务,而不是只会 copy-paste 代码

4.1 用场景解析.jpg讲清“为什么用随机森林,而不是 XGBoost”

场景解析.jpg不是随便画的架构图,它是本项目的业务逻辑锚点。答辩时别一上来就说“我用了 RF”,而是指着图中“特征输入层”说:

“老师您看,V1-V28 是银行实时风控引擎输出的 28 个中间指标,它们之间存在强耦合(比如 V3 和 V7 相关性达 0.92),XGBoost 的梯度提升容易放大这种耦合噪声;而随机森林的 bagging 机制天然对特征冗余不敏感,且单棵树的可解释性让我们能定位到‘V17 异常升高’是欺诈的关键判据——这在lg.png的特征重要性排序里排第 2。”

然后翻到lg.png(特征重要性图),用激光笔圈出 V17,再切到反欺诈模型.html中对应树的路径,展示“V17 > -1.2 → V22 < 0.8 → Class=1”的决策路径。这才是老师想听的“业务-技术”闭环,不是“我调了 100 个参数”。

4.2 用阈值.png回答“你们模型漏报率多少?银行能接受吗?”

阈值.png的横轴是阈值,纵轴是 Precision/Recall/F1。答辩时不要只说“我们选了 0.18”,而是画一条虚线:

# 在阈值图中添加业务红线 plt.axhline(y=0.85, color='red', linestyle='--', label='银行可接受最低召回率(85%)') plt.axvline(x=optimal_threshold, color='green', linestyle='-', label=f'选定阈值={optimal_threshold:.3f}') plt.legend()

然后说:

“根据银保监《反洗钱技术指引》,单笔欺诈交易漏报成本是误报成本的 20 倍以上。所以我们设定召回率底线为 85%,此时精确率为 62%——意味着每拦截 100 笔可疑交易,有 38 笔是正常交易,但漏掉的欺诈不足 15 笔。这个权衡在阈值.png的绿色竖线处达成,F1 得分 0.71,是精度与召回的帕累托最优。”

4.3 把项目思路.jpg改成“问题-方法-验证”三角模型,一页讲清毕设价值

项目思路.jpg原图是线性流程(数据→清洗→建模→评估),答辩时重绘为三角形:

顶点内容对应资源
问题“信用卡欺诈样本稀疏且特征高维,传统规则引擎漏报率超 40%”目标变量可视化.png(欺诈占比 0.17%)+场景解析.jpg(规则引擎局限)
方法“用 SMOTE 解决样本不平衡,用 V 系列零值计数构造业务特征,用 PR 曲线替代 ROC 选阈值”smote.jpg+缺失值.png+Pr——Re.png
验证“在测试集上召回率达 86.3%,较基线逻辑回归提升 22 个百分点,且误报率可控在 38%”反欺诈模型.ipynb输出结果 +lg.png特征重要性佐证

提示:把这张重绘图放进项目报告.pptx第 3 页,标题写“本项目解决的核心矛盾”,比“系统架构图”有力十倍。


5. 二次开发实战:如何把这份代码改成你自己的毕设课题,附赠三个已验证的拓展方向

5.1 方向一:从“信用卡欺诈”迁移到“信贷申请欺诈”,只需替换三处数据接口

信贷场景的欺诈数据(如 Lending Club 公开数据集)与信用卡最大区别是:特征维度少(<10 个)、文本字段多(职业、教育)、时间序列强(还款历史)。改造步骤:

  1. 替换数据加载模块:

    # 原 creditcard.csv 加载 df = pd.read_csv('creditcard.csv') # 改为信贷数据(示例) df = pd.read_csv('loan_data.csv') # 重点:提取 'emp_title'(职业描述)做 TF-IDF from sklearn.feature_extraction.text import TfidfVectorizer tfidf = TfidfVectorizer(max_features=100, stop_words='english') emp_tfidf = tfidf.fit_transform(df['emp_title'].fillna(''))
  2. 调整特征工程:

    • 删除V1-V28相关代码;
    • 对loan_amnt、annual_inc做 log 变换;
    • 将emp_tfidf矩阵与数值特征 concat。
  3. 修改评估逻辑:
    信贷欺诈更关注“首期违约”,所以Class列应定义为loan_status == 'Charged Off',且需用TimeSeriesSplit替代StratifiedKFold(因时间依赖性)。

我帮西电一位同学做过此迁移,最终在 Kaggle Lending Club 数据上达到 0.89 AUC,项目报告.pptx中“拓展应用”页可直接复用原 PPT 框架。

5.2 方向二:加入图神经网络(GNN)捕捉交易关联性,用 PyTorch Geometric 实现

当前模型是孤立交易判断,但真实欺诈常呈团伙作案(同一设备、IP、收款账户)。拓展方案:

模块原代码位置替换方案验证资源
数据构建反欺诈模型.ipynb开头用networkx构建交易图:节点=用户/商户,边=交易,权重=金额场景解析.jpg中“团伙欺诈”示意图可作引子
模型RandomForestClassifier替换为GCNConv层堆叠,输入=节点特征(Amount、Time),输出=节点欺诈概率需新增requirements_gnn.txt(含 torch-geometric)
评估classification_report加入roc_auc_score(因 GNN 输出概率更平滑)Pr——Re.png仍适用,但曲线更陡峭

注意:GNN 训练慢,建议先用torch_geometric.loader.NeighborLoader采样子图,否则 28 万节点显存爆炸。反欺诈模型.html可保留为 GNN 的可解释性补充(展示关键邻居节点)。

5.3 方向三:部署为 Flask API,用 Docker 封装成可演示系统

毕设答辩常被问“怎么落地”,光有 notebook 不够。三步封装:

  1. 写 API 接口(app.py):

    from flask import Flask, request, jsonify import joblib import pandas as pd app = Flask(__name__) model = joblib.load('best_model.pkl') # 由 grid_search.best_estimator_ 保存 scaler = joblib.load('scaler.pkl') @app.route('/predict', methods=['POST']) def predict(): data = request.json df = pd.DataFrame([data]) # 输入格式:{"V1":0.1,"V2":-0.2,...,"Amount":120.5} scaled = scaler.transform(df) pred = model.predict_proba(scaled)[:, 1] return jsonify({"fraud_probability": float(pred[0])})
  2. 写 Dockerfile:

    FROM python:3.8-slim COPY requirements.txt . RUN pip install -r requirements.txt COPY . /app WORKDIR /app CMD ["gunicorn", "--bind", "0.0.0.0:5000", "app:app"]
  3. 一键启动:

    docker build -t fraud-api . docker run -p 5000:5000 fraud-api curl -X POST http://localhost:5000/predict -H "Content-Type: application/json" -d '{"V1":0.1,"V2":-0.2,"Amount":120.5}'

提示:项目报告.pptx最后一页加“系统演示”视频截图(录屏 10 秒 curl 请求),比 20 页技术细节更有说服力。说明.md中已预留API 部署指南章节,填空即可。

从那以后我每次带学生做毕设,都会强制他们在反欺诈模型.ipynb里跑通Pr——Re.png和阈值.png生成逻辑——不是为了交差,而是确保他们真正理解:在金融场景里,模型不是越准越好,而是要在业务容忍的代价下,把漏报控制在生死线上。这份资源的价值,不在于它给了你一个模型,而在于它把这条生死线,用 12 张图、3 个脚本、1 份 PPT,钉死在你眼前。希望帮到你。

本文还有配套的精品资源,点击获取

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询