ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

金融反欺诈机器学习实战:不平衡分类与模型评估全流程

金融反欺诈机器学习实战:不平衡分类与模型评估全流程 简介这是一套基于Python与机器学习的金融反欺诈检测完整资源包包含源码、开发文档说明与数据报告面向期末作业、课程设计或项目开发场景适合需要上手完整建模流程的初学者与进阶者。项目以金融交易数据为对象覆盖缺失值处理、特征筛选与标准化等预处理环节引入SMOTE采样缓解不平衡数据问题并通过stacking集成学习完成欺诈识别建模代码经严格测试可放心参考并二次扩展。压缩包共17个文件大小约66.7MB主体为2个ipynb模型代码与1个md开发说明另附项目报告pptx、模型可视化html、原始数据rar及多张实验图表便于对照复现与成果展示。已有192人浏览学习。借助配套可视化图表、报告模板与README说明能快速理清数据预处理、不平衡采样、集成建模等模块的衔接是期末答辩、课程汇报或简历项目的落地参考。目录层次清晰从数据导入到模型评估均有对应文件适合快速搭建演示环境。1. 金融反欺诈检测这门课设到底在训练什么答辩现场最容易出现的尴尬不是模型跑不出来而是老师问了一句“你的准确率 99.7%为什么还要做反欺诈” 你要是答不上来前面熬的夜全白费。基于 python机器学习做的金融反欺诈检测本质上是训练一个二分类模型去识别交易数据里的欺诈样本但它最大的特点不是“准确”而是数据极度不平衡——一万笔交易里可能只有几笔是欺诈。这门课设的完整交付物包括可运行的源码、开发文档说明和数据报告多数是期末大作业或课程设计的形式。它适合机器学习入门者练手也适合拿来做毕业设计的预研数据量不大、模型选型空间充足、评估指标有讲头从数据处理到答辩演示能形成完整闭环。这篇笔记按我实际做过的方案从数据探索、模型训练、评估到写文档一条线走完。2. 拿到信用卡欺诈数据先别急着跑模型数据探索与特征准备的完整流程2.1 数据长什么样从读入到 EDA 的最少代码金融反欺诈检测最常用的公开数据集是信用卡交易记录特征是经过 PCA 降维后的数值型变量标签只有 0 和 1。这类数据集的优点是干净缺点是太干净——你不用做太多特征工程反而更容易把精力放在建模和评估上。拿到数据第一步不是建模而是搞清楚三件事样本量多大、正负样本比例多少、有没有缺失值。用 pandas 几行代码就能看明白import pandas as pd df pd.read_csv(creditcard.csv) print(df.shape) # (284807, 31) print(df.isnull().sum().sum()) # 缺失值总数 print(df[Class].value_counts(normalizeTrue))从输出能直接看到负样本占比往往在 0.1% 到 1% 之间这就是金融反欺诈检测和普通分类任务最本质的区别。这一步的产出是一个数字欺诈样本占多少。后面所有模型选型、评估指标、阈值调整都围绕这个比例展开。2.2 为什么金融反欺诈必须做标准化Amount 与 PCA 特征的尺度差异这个数据集的绝大多数字段 V1 到 V28 是 PCA 变换后的结果均值在 0 附近、方差接近 1但 Amount交易金额字段是原始数值范围可能从 0.01 到几万。如果不做标准化基于距离和梯度的模型会天然偏向金额大的样本逻辑回归的系数也会被尺度带偏。from sklearn.preprocessing import StandardScaler scaler StandardScaler() df[Amount_scaled] scaler.fit_transform(df[Amount].values.reshape(-1, 1)) df df.drop([Amount, Time], axis1) # Time 对欺诈检测帮助有限直接删掉这里有两个细节。第一fit_transform是对 Amount 单独做的因为 V1 到 V28 已经是标准化后的结果不需要再动。第二Time 字段表示交易时间间隔在大多数课设场景下对分类没有直接贡献删掉可以降低噪声如果你有兴趣也可以把它拆成“小时”或“星期”这种周期性特征做尝试。特征的尺度问题直接影响模型收敛速度特别是用逻辑回归或神经网络的时候不标准化的后果是 loss 下降慢、系数解释性差。2.3 训练集 / 验证集划分时间顺序比随机划分更接近真实场景很多教程直接train_test_split(df, test_size0.2)随机切分这在金融反欺诈场景里是错的。原因是交易数据天然带时间属性随机划分会让模型“看到未来”——训练集里混入了时间上更晚的样本验证集里却出现了更早的数据这相当于开卷考试。df df.sort_values(Time).reset_index(dropTrue) split_idx int(len(df) * 0.8) train df.iloc[:split_idx] test df.iloc[split_idx:] X_train train.drop(Class, axis1) y_train train[Class] X_test test.drop(Class, axis1) y_test test[Class]我一般会先按Time排序再取前 80% 做训练、后 20% 做验证。这样模拟的是“用过去的数据预测未来的交易”和真实风控系统的上线流程一致。答辩时如果你能主动说出这个理由老师会认为你不是在照搬代码而是理解了这个场景的业务逻辑。另外这里排序用的Time是原始字段所以上一步先别急着删等切分完再删也不迟。3. 用逻辑回归和 XGBoost 搭出第一个可运行的反欺诈模型3.1 逻辑回归做基线金融风控开场为什么多是它金融反欺诈检测的入门模型我几乎总是先跑逻辑回归。原因有三训练快、可解释性强、对不平衡数据有天然的应对手段。逻辑回归输出的是概率而不是硬分类这在风控场景里非常有用——你可以拿概率去卡阈值而不是被迫接受 0/1 的判决。另一个重要原因是class_weight参数它能在不改变数据分布的前提下让模型更关注少数类。from sklearn.linear_model import LogisticRegression from sklearn.metrics import roc_auc_score lr LogisticRegression(class_weightbalanced, max_iter500) lr.fit(X_train, y_train) y_prob lr.predict_proba(X_test)[:, 1] print(AUC:, roc_auc_score(y_test, y_prob))class_weightbalanced会自动按类别频率反比调整权重少数类样本的损失被放大模型不再“躺平”把所有样本都预测成正常交易。max_iter500是为了给收敛留足迭代空间因为标准化后的高维特征虽然收敛快但默认的 100 次有时不够。这一步跑完AUC 通常能到 0.95 以上说明逻辑回归在这个任务上已经有不错的区分度了。3.2 给 XGBoost 调三个参数从过拟合拉回泛化逻辑回归做基线没问题但要想在课设里体现“我做了模型对比”XGBoost 是第二梯队的最佳选择。它训练快、对特征交互敏感、自带正则化缺点是需要调的参数比逻辑回归多。我一般只动三个参数其他保持默认from xgboost import XGBClassifier xgb XGBClassifier( n_estimators200, max_depth5, scale_pos_weight99, # 负样本≈99倍于正样本时使用 learning_rate0.1, eval_metricauc, use_label_encoderFalse ) xgb.fit(X_train, y_train) y_prob_xgb xgb.predict_proba(X_test)[:, 1] print(XGB AUC:, roc_auc_score(y_test, y_prob_xgb))scale_pos_weight的作用和逻辑回归的class_weight类似它让 XGBoost 在计算梯度时给少数类更大的权重。这个值一般取负样本数除以正样本数你可以自己算完填进去。max_depth5控制树的深度太深容易过拟合learning_rate0.1配合n_estimators200是折中方案。跑完后看 AUC 是否比逻辑回归有提升——有提升就把它当最终模型没提升就用逻辑回归当最终模型毕竟答辩时“能解释清楚”比“分数高一点”更重要。3.3 类别不平衡的两种处理class_weight 与 SMOTE 的取舍遇到类别不平衡很多人第一时间想到 SMOTE合成少数类过采样。但我要泼一盆冷水SMOTE 在这类 PCA 特征数据集上的收益可能不大而且用它之前必须想清楚评估方式会不会泄漏。from imblearn.over_sampling import SMOTE from sklearn.model_selection import train_test_split # 只对训练集做过采样测试集保持原样 X_train_sm, y_train_sm SMOTE(random_state42).fit_resample(X_train, y_train) print(y_train_sm.value_counts())这里最容易犯的错是对全量数据做过采样再切分这属于典型的评估泄漏后面避坑章节会专门讲。SMOTE 的核心逻辑是在少数类样本之间插值生成新样本让正负样本比例接近 1:1但它生成的是“假数据”不一定符合真实欺诈分布。我的做法是先跑一个class_weight或scale_pos_weight的版本再跑一个 SMOTE 版本对比 AUC 和召回率用结果说话。如果两者差不多优先选择前者因为代码更简洁、答辩时更好解释。4. 反欺诈模型的真正考题召回率、精准率与 AUC 的读法4.1 accuracy 是陷阱0.17% 的欺诈率下读准确率没有意义金融反欺诈检测的评估环节是区分“真懂”和“照葫芦画瓢”的分水岭。假设你的模型把所有交易都预测为正常准确率是 99.83%——听起来很优秀但这个模型毫无价值因为它漏掉了所有欺诈。所以我从来不在答辩里说“准确率有多高”而是用 AUC、召回率和精准率说话。from sklearn.metrics import classification_report, confusion_matrix y_pred (y_prob_xgb 0.5).astype(int) print(classification_report(y_test, y_pred, target_names[正常, 欺诈])) print(confusion_matrix(y_test, y_pred))classification_report会输出每个类别的 precision、recall 和 f1-score其中欺诈类的召回率是最重要的指标——它代表“100 笔欺诈里能抓出多少”。如果召回率低于 0.5说明模型在漏案子这在风控场景里是不可接受的。阈值 0.5 是 scikit-learn 的默认值但在极度不平衡数据上它往往不是最优选择所以下一步要调阈值。4.2 用混淆矩阵和 PR 曲线挑阈值让模型按业务要求“偏科”贷款风控关心的是误伤率——把好客户拦下来是损失但反欺诈更关心的是漏检率——放过一个坏人可能造成更大损失。这两个诉求在阈值上是互斥的你只能在“多抓”和“少错杀”之间取一个平衡点。import numpy as np from sklearn.metrics import precision_recall_curve precisions, recalls, thresholds precision_recall_curve(y_test, y_prob_xgb) best_f1 0 best_threshold 0.5 for t, p, r in zip(thresholds, precisions[:-1], recalls[:-1]): f1 2 * p * r / (p r) if (p r) 0 else 0 if f1 best_f1: best_f1 f1 best_threshold t print(Best F1:, best_f1, Threshold:, format(best_threshold, .4f))这段代码遍历所有可能阈值找出 F1 分数最高对应的截断点。在实际课设里你可以把“业务规则”写得更具体比如“召回率不低于 0.8 的前提下尽量提高精准率”然后据此选阈值。调阈值这件事本身不需要重新训练模型它只改变判决边界所以你可以公开这样做——答辩时讲清楚“我为了业务目标选择了 0.3 而不是 0.5”比单贴一个模型结果更有说服力。4.3 导出模型文件与预测结果给答辩留好“后悔药”课设通常要现场演示最尴尬的情况是环境崩了、模型丢了。把训练好的模型保存到本地文件是个好习惯答辩前哪怕代码重跑也能直接加载模型文件输出预测结果。import joblib joblib.dump(xgb, fraud_model.pkl) # 加载模型对单笔交易做预测 # loaded_model joblib.load(fraud_model.pkl) # sample X_test.iloc[[0]] # prob loaded_model.predict_proba(sample)[:, 1] # print(欺诈概率:, prob[0])保存模型之后再做一步“预测结果落地”——把测试集的预测概率和原始标签拼在一起导出成 CSV。这样做有两个好处一是答辩时可以直接展示“模型在这 5000 条未来数据上抓出了多少欺诈”二是如果答辩时有人质疑结果你有数据文件可以现场复盘不至于翻车。5. 金融反欺诈开发中的 5 个高频踩坑从数据泄漏到过拟合5.1 坑一SMOTE 过采样后直接切测试集——训练泄漏现象用 SMOTE 处理完整数据集后再随机切分训练集和测试集AUC 高达 0.999答辩时被老师一问就露馅。原因SMOTE 生成的合成样本同时进入了训练集和测试集模型在“看到过”的样本上做评估分数虚高。解决先切分再对训练集单独过采样测试集必须保持原始分布。这是我反复强调的一点也是最容易忽略的评估泄漏。5.2 坑二StandardScaler 在全量数据上 fit——标准化泄漏现象训练时 AUC 正常但对新数据做预测时效果暴跌。原因scaler.fit_transform(df[Amount])使用了全量数据的均值和标准差相当于测试集的信息被训练阶段“偷看”了。这比 SMOTE 泄漏更隐蔽因为很多人根本想不到标准化也算泄漏。解决先切分数据再对训练集的Amount字段fit然后用训练集的均值和标准差transform测试集。代码就三行但顺序不能错scaler StandardScaler().fit(X_train[Amount].values.reshape(-1, 1)) X_train[Amount_scaled] scaler.transform(X_train[Amount].values.reshape(-1, 1))5.3 坑三无视类别不平衡直接调默认参数——模型“躺平”现象模型跑完AUC 挺高但看混淆矩阵发现欺诈类召回率是 0模型把所有样本都预测为正常。原因默认参数下模型优化的是整体准确率欺诈样本占比太低模型发现“全部预测为正常”损失最小于是躺平。解决逻辑回归用class_weightbalancedXGBoost 用scale_pos_weight99或者在训练前确认正负样本比例。不要迷信 AUC 高就是好模型——AUC 只看排序不看过拟合程度和实际判决行为是两回事。5.4 坑四随机划分训练集——时间维度“剧透”现象模型在验证集上召回率达到 0.9但放到真实场景里效果大幅下降。原因随机切分让训练集和测试集来自同一时间段模型学到了“时间段特征”而非“交易特征”。真实场景要用历史数据预测未来时间错位后就失灵了。解决严格按照Time排序后前 80% 训练、后 20% 验证。如果数据集没有时间字段则不要使用该字段做随机划分以外的任何处理并在文档里说明这一假设。5.5 坑五阈值调到召回率等于 1——误伤率爆表现象为了让召回率变成 1把阈值降到 0.1结果正常交易也被大量拦下业务上不可用。原因调阈值一味追求单指标忽视了风控的真实约束。真实场景里误伤过多会导致用户流失和投诉甚至超过欺诈造成的损失。解决调阈值时参考 PR 曲线设定“误伤率上限”或“召回率下限”在这两个约束内取最优。比如“召回率不低于 0.8 时精准率最高”的阈值就是合理选择。把这条逻辑写进报告答辩反而加分。6. 把课设做成能答辩的交付物开发文档、数据报告与演示路径6.1 开发文档怎么写从环境到复现结果一节不落很多人的开发文档是答辩前草草补的这很吃亏。真正加分的是“环境能复现、结果能验证”的说明即使代码写得不那么完美文档完整也能弥补印象分。# 金融反欺诈检测系统 ## 运行环境 - Python 3.8 - pandas1.5.3 / numpy1.24.3 / scikit-learn1.2.2 - xgboost1.7.5 / imblearn0.10.1 ## 文件结构 - src/data_processing.py # 数据读取、清洗、切分 - src/train.py # 模型训练与保存 - src/evaluate.py # 评估指标计算与阈值调整 - data/creditcard.csv # 原始数据集 ## 运行步骤 1. python src/data_processing.py # 生成 X_train, X_test 2. python src/train.py # 训练并保存 fraud_model.pkl 3. python src/evaluate.py # 输出评估结果与阈值 ## 结果复现 - AUC: 0.97XGBoost - 召回率欺诈: 0.82 threshold0.3这份文档的核心价值是第三人称“可验证性”——任何人按这个步骤跑一遍能得出和你报告中一致的数字。写文档时把每条结论都挂上对应脚本名比大段理论描述有用得多。6.2 数据报告的核心图表从数据分布到模型结论数据报告不是代码日志的堆砌而是回答四个问题数据长什么样、模型怎么选的、效果如何、业务上意味着什么。以下五张图表足以撑起一份课设报告图表解决的问题生成工具类别分布柱状图直观展示不平衡程度matplotlib / seaborn特征相关性热力图说明 PCA 特征之间独立性seaborn逻辑回归与 XGBoost 的 ROC 曲线对比支撑模型选型结论matplotlibPR 曲线展示不同阈值下的精准率 / 召回率权衡matplotlib混淆矩阵热力图展示最终模型在测试集上的表现seaborn每张图配一段两三句话的解读重点不是“它是什么图”而是“从图里看出了什么所以接下来怎么做”。比如“类别分布显示欺诈占比 0.17%因此评估指标放弃 accuracy 改用 AUC 和召回率”——把图和决策串起来报告就有血有肉了。6.3 答辩演示的 20 分钟路径从数据到结论一气呵成答辩演示的时间分配很重要。我建议按“2 分钟背景— 5 分钟数据 — 5 分钟模型 — 5 分钟评估 — 3 分钟总结与展望”来安排这样既覆盖了项目的完整闭环又给每部分留了讲清楚的时间。演示时手里要准备一页“模型好坏怎么界定”的说明——这往往是答辩老师最关注的你的模型到底好在哪是比逻辑回归好了多少还是比随机猜测好了多少用数字回答不要用形容词。我的习惯是开场直接说“这个项目解决的是信用卡交易中的欺诈识别问题我选择了 XGBoost 模型在测试集上 AUC 0.97欺诈类召回率 0.82。下面看数据是怎么支撑这个结论的。” 然后按数据分布、基线模型、调阈值、最终结论走一遍全程不超过 20 分钟。这套路的终点是“可复现的交付物”——代码、文档、报告三件套齐全实验数字经得起验证你就不怕任何追问。做这种机器学习课设最怕的不是模型跑不出来而是不知道好模型长什么样、文档和报告该怎么组织。把重心放在数据切分、评估指标和文档可复现性上这个项目的底线就守住了。希望帮到你。本文还有配套的精品资源点击获取
返回列表