简介这份资源面向计算机、数据科学、人工智能等专业的在校学生与教师以及需要金融风控入门实践的开发者提供一套基于机器学习实现金融反欺诈检测的完整Python项目。压缩包共17个文件约133.46MB包含2个ipynb代码笔记、1份pptx项目报告、1个html模型页面、1个md说明文档以及png、jpg等模型图例与可视化素材另有数据压缩包辅助复现。项目围绕信用卡交易欺诈识别展开涵盖缺失值处理、SMOTE样本均衡、GridSearchCV调参、阈值选择与PR—Re曲线评估等关键环节并配有目标变量分布、直方图、场景解析等图示便于理解建模思路。已有171人学习下载可作为课程设计、大作业、毕业设计或初期项目立项的参考模板也适合在此基础上进行二次开发与拓展实验。1. 金融反欺诈检测为什么总在“离线准、上线崩”上翻车很多团队第一次做金融反欺诈检测都会经历同一个剧本拿一份历史交易流水用 Python 跑个逻辑回归或 XGBoost离线 AUC 冲到 0.95PPT 报告写得漂漂亮亮结果一上线拦截率没涨多少误杀率倒是把客服打爆了。问题不在模型在于反欺诈本质是一个极度不平衡、强对抗、且带时间漂移的序列决策问题而多数人把它当成了普通二分类。这个标题里的“基于机器学习实现的金融反欺诈检测 python 源码含说明PPT 报告”拆开看其实是三件事一套能跑通的数据处理与建模流程、一份能讲清楚业务逻辑的说明文档、一份能说服风控和业务方的汇报材料。它适合两类人一类是刚入门机器学习、想找一个真实场景练手的同学另一类是已经会调库、但没系统做过风控落地的工程师。接下来我不讲空泛概念直接按“数据怎么洗、特征怎么造、模型怎么选、阈值怎么定、坑在哪”这条线把一套可复现的方案讲透。2. 反欺诈数据从原始流水到建模宽表采样与特征工程2.1 为什么不能直接拿原始交易表喂模型原始交易流水通常是“一行一笔”的长表字段包括用户 ID、商户 ID、时间戳、金额、设备指纹、IP、交易结果等。直接丢进模型会有三个致命问题一是正负样本比例可能到 1:1000 甚至更极端模型会倾向于全预测为正常二是同一用户的多笔交易之间存在强相关随机划分训练测试集会导致信息泄露三是原始 ID 类字段维度极高独热编码后稀疏到无法训练。常见做法是先做用户级聚合把“一笔交易”变成“一个用户在一个时间窗口内的行为画像”。比如以 7 天为窗口统计该用户的交易笔数、金额均值、金额标准差、夜间交易占比、失败率、常用设备数、常用 IP 数等。这样既降低了样本量又让每条样本代表一个相对完整的行为模式。import pandas as pd import numpy as np # 假设 raw 是原始交易流水包含 user_id, trade_time, amount, status, device_id, ip raw[trade_time] pd.to_datetime(raw[trade_time]) raw raw.sort_values([user_id, trade_time]) # 标记标签假设 fraud_label 在用户维度给出这里先聚合到用户 user_label raw.groupby(user_id)[fraud_label].max().reset_index() # 按用户做 7 天窗口聚合 def build_user_features(df): g df.groupby(user_id) feat pd.DataFrame({ trade_cnt: g.size(), amount_mean: g[amount].mean(), amount_std: g[amount].std(), amount_max: g[amount].max(), fail_rate: g[status].apply(lambda x: (x fail).mean()), night_ratio: g[trade_time].apply(lambda x: ((x.dt.hour 22) | (x.dt.hour 6)).mean()), device_cnt: g[device_id].nunique(), ip_cnt: g[ip].nunique(), }).reset_index() return feat user_feat build_user_features(raw) data user_feat.merge(user_label, onuser_id, howleft)这段代码的逻辑是先按时间排序保证窗口内统计的顺序正确再用groupby把交易级数据压缩成用户级特征。amount_std为空说明该用户只有一笔交易后续要填充 0night_ratio用小时判断夜间交易是反欺诈里非常强的信号因为盗刷和欺诈团伙常集中在凌晨操作。参数上窗口长度 7 天不是固定的如果业务交易频率高可以缩到 1 天如果低频可以放到 30 天但要注意时间跨度太长会引入行为漂移。2.2 不平衡采样过采样、欠采样还是代价敏感反欺诈场景下正样本欺诈往往只占千分之几。直接训练会让模型把所有样本判为正常准确率看着高但召回率接近零。常见处理方式有三种随机欠采样、SMOTE 过采样、以及直接在模型里设置class_weight或scale_pos_weight。我的经验是优先用代价敏感学习而不是盲目过采样。因为 SMOTE 在超高维稀疏特征上容易生成不真实的合成样本反而让模型学到噪声。XGBoost 和 LightGBM 都支持scale_pos_weight把它设为负样本数除以正样本数通常能直接把召回率拉起来。from sklearn.model_selection import train_test_split from xgboost import XGBClassifier # 按时间划分而不是随机划分避免未来信息泄露 data data.sort_values(user_id) # 实际应按首次交易时间排序 train, test train_test_split(data, test_size0.3, random_state42, stratifydata[fraud_label]) X_train train.drop([user_id, fraud_label], axis1).fillna(0) y_train train[fraud_label] X_test test.drop([user_id, fraud_label], axis1).fillna(0) y_test test[fraud_label] # 计算正负样本比例 scale (y_train 0).sum() / (y_train 1).sum() model XGBClassifier( n_estimators300, max_depth5, learning_rate0.05, scale_pos_weightscale, eval_metricauc, use_label_encoderFalse ) model.fit(X_train, y_train)这里scale_pos_weight直接决定了模型对正样本的敏感度。设得太大误杀会飙升设得太小召回上不去。一般从负正比开始试再根据业务能接受的误杀率微调。max_depth控制在 5 左右是为了防止过拟合反欺诈特征里很多是统计量树太深容易记住特定用户。eval_metric用 AUC 而不是准确率因为不平衡场景下准确率没有参考价值。2.3 特征工程里最容易被忽略的三类信号除了常规的金额和频次反欺诈里真正拉开差距的是设备聚集度、时间聚集度、以及关系网络特征。设备聚集度指同一设备关联了多少个用户欺诈团伙常共用设备时间聚集度指同一时间段内有多少用户集中注册或交易关系网络特征则是把用户和设备、IP 构建成二部图计算连通分量大小。# 设备聚集度同一设备关联的用户数 device_user_cnt raw.groupby(device_id)[user_id].nunique().reset_index() device_user_cnt.columns [device_id, device_user_cnt] raw raw.merge(device_user_cnt, ondevice_id, howleft) # 时间聚集度同一小时内交易笔数 raw[hour_bucket] raw[trade_time].dt.floor(H) hour_cnt raw.groupby(hour_bucket).size().reset_index(namehour_trade_cnt) raw raw.merge(hour_cnt, onhour_bucket, howleft)这两个特征在实战中非常有效因为正常用户的设备通常只关联自己而欺诈设备可能关联几十个账号。hour_trade_cnt突然飙升往往意味着批量攻击。注意这些特征要在训练集和测试集上分别计算或者用历史窗口滚动计算否则会引入未来信息。3. 模型选型与阈值调优从 AUC 到业务拦截率3.1 逻辑回归、树模型还是图神经网络在金融反欺诈里模型选型不是越复杂越好。逻辑回归可解释性强适合监管要求高的场景XGBoost/LightGBM 在结构化特征上表现稳定是大多数团队的首选图神经网络适合关系网络明显的团伙欺诈但工程复杂度高落地周期长。如果只是做一份能讲清楚流程的源码和报告我建议主模型用 LightGBM辅以逻辑回归做基线对比。LightGBM 训练快、内存占用低且自带特征重要性输出方便在 PPT 里解释“哪些行为最像欺诈”。import lightgbm as lgb from sklearn.metrics import roc_auc_score, precision_recall_curve lgb_model lgb.LGBMClassifier( n_estimators500, num_leaves31, learning_rate0.05, scale_pos_weightscale, subsample0.8, colsample_bytree0.8, random_state42 ) lgb_model.fit(X_train, y_train) y_prob lgb_model.predict_proba(X_test)[:, 1] print(AUC:, roc_auc_score(y_test, y_prob)) # 找最佳阈值在召回和误杀之间取平衡 precision, recall, thresholds precision_recall_curve(y_test, y_prob) f1 2 * precision * recall / (precision recall 1e-8) best_threshold thresholds[f1.argmax()] print(Best threshold:, best_threshold)num_leaves控制树的复杂度31 是常用起点subsample和colsample_bytree用来增加随机性、防止过拟合。precision_recall_curve帮我们找到 F1 最大的阈值但实际业务里不能只看 F1还要看误杀一个正常用户带来的客服成本和声誉损失。通常会把阈值定在召回 80% 时对应的点再根据人工审核能力调整。3.2 阈值不是拍脑袋用业务成本反推很多源码里直接写threshold 0.5这在反欺诈里基本是错的。正确做法是构建一个简单的成本矩阵拦截一个欺诈带来的收益是避免的损失金额误杀一个正常用户带来的成本是客服处理加用户流失。用这两个值反推最优阈值。# 假设欺诈平均损失 500 元误杀成本 50 元 cost_fraud 500 cost_false_alarm 50 best_cost float(inf) best_th 0 for th in np.arange(0.01, 1.0, 0.01): pred (y_prob th).astype(int) fp ((pred 1) (y_test 0)).sum() fn ((pred 0) (y_test 1)).sum() total_cost fp * cost_false_alarm fn * cost_fraud if total_cost best_cost: best_cost total_cost best_th th print(Cost-optimal threshold:, best_th)这段代码把阈值选择和业务成本直接挂钩比单纯看 F1 更贴近实际。cost_fraud和cost_false_alarm需要和风控业务方一起定不同业务差异很大。比如信贷场景欺诈损失高阈值会偏低支付场景误杀影响大阈值会偏高。3.3 模型可解释性SHAP 值怎么放进 PPT风控和业务方不会接受一个黑匣子。用 SHAP 输出每个特征对单笔预测的贡献既能做bad case分析也能直接放进 PPT 报告。import shap explainer shap.TreeExplainer(lgb_model) shap_values explainer.shap_values(X_test) # 全局特征重要性 shap.summary_plot(shap_values, X_test, plot_typebar) # 单个样本解释 shap.force_plot(explainer.expected_value, shap_values[0], X_test.iloc[0])TreeExplainer对树模型计算很快summary_plot的 bar 图可以直接截图放进 PPT说明“设备关联用户数”和“夜间交易占比”是主要驱动因素。force_plot适合解释某个具体用户为什么被拦截客服和审核人员能看懂。4. 避坑与排查反欺诈模型上线前后最容易踩的五个坑4.1 现象离线 AUC 0.95上线后召回不到 30%原因通常是训练集和线上特征计算逻辑不一致。离线用全量数据算统计量线上只能拿到当前时间点之前的数据导致特征分布偏移。解决方法是统一用滚动窗口计算特征并在训练时模拟线上可用的历史窗口。4.2 现象模型把大量老用户判为欺诈原因是老用户的历史行为丰富统计特征如交易笔数、设备数天然偏高而模型把“高活跃”误学成了“高风险”。解决方法是在特征里加入用户年龄或注册时长做归一化或者对老用户单独建模型。4.3 现象阈值调完后误杀率降了但欺诈损失涨了这是典型的成本权衡没做好。解决方法是把误杀和漏判的成本写进评估脚本每次调阈值都看总成本而不是只看单一指标。同时要和业务方确认可接受的最大误杀率。4.4 现象SHAP 图显示某个特征重要性极高但业务上说不通可能是数据泄露。比如“是否有人工审核记录”这个特征在欺诈样本里几乎都是 1因为欺诈用户会被人工审核但线上预测时这个特征根本拿不到。解决方法是逐个检查高重要性特征在预测时是否真实可得。4.5 现象模型上线后性能逐月下降反欺诈是强对抗场景欺诈团伙会不断调整策略。解决方法是建立定期重训练机制比如每月用最近三个月数据重新训练并监控特征分布漂移PSI。PSI 超过 0.2 就要警惕。5. 把源码和 PPT 串成一条线复现时我坚持的三个习惯第一先跑通再优化。不要一上来就调参先用默认参数跑一遍全流程确认数据管道、特征计算、模型训练、评估输出都能跑通再逐步加特征和调参。我见过太多人卡在环境配置和路径错误上最后连基线都没跑出来。第二每个特征都要能回答“线上怎么算”。写代码时我会在特征旁边注释数据来源和计算窗口比如# 近7天夜间交易占比线上用Flink滑动窗口。这样在写 PPT 报告时直接把这些注释整理成表格业务方一看就懂。第三PPT 报告只讲三件事问题、方案、效果。问题部分用一张图说明欺诈损失和误杀现状方案部分用流程图展示数据到模型的链路重点标出特征工程和阈值策略效果部分用表格对比基线模型和最终模型的 AUC、召回、误杀率和成本节省。不要堆公式不要贴大段代码。# 一个简单的效果对比表生成脚本 import pandas as pd result pd.DataFrame({ 模型: [逻辑回归, LightGBM], AUC: [0.82, 0.91], 召回率: [0.55, 0.78], 误杀率: [0.03, 0.05], 预估成本节省: [12000, 35000] }) print(result.to_markdown(indexFalse))这张表可以直接放进 PPT比任何文字都有说服力。成本节省的算法是拦截欺诈带来的损失减少减去误杀带来的客服成本具体数值按业务实际填。最后说一个我自己的习惯每次做完一个反欺诈模型我都会把阈值、特征列表、训练数据时间范围写进一个model_card.md和源码放在一起。过三个月再回头看不用翻聊天记录就知道当时为什么这么定。希望帮到你。本文还有配套的精品资源点击获取
阅读完成 · 觉得有帮助?