Creditcard_Fraud_project
信用卡欺诈检测项目从零复现:完整代码讲解与结果分析
本文基于 Kaggle 信用卡欺诈数据集,从环境搭建开始,一步步带你复现一个完整的机器学习项目:EDA、数据预处理、SMOTE 不平衡处理、5 个模型对比、阈值调优、特征重要性分析。
文中所有截图都是本机运行的真实结果,图片位于
source/img/04Creditcard_Fraud/目录。如果你把这篇文档发到博客,请记得把图片目录一起上传,或者把图片换成你自己的图床链接。
目录
- 项目背景与目标
- 环境准备
- 项目结构与整体流程
- 分步代码讲解
- 复现结果汇总
- 常见问题
- 总结与改进方向
一、项目背景与目标
信用卡欺诈是金融风控中最典型的场景之一:每天有海量交易发生,其中欺诈交易占比极低,但一旦发生就会造成资金损失。机器学习要解决的核心问题是:
在几万笔交易中,准确找出那几笔“有问题”的交易,同时尽量不打扰正常用户。
这个任务有两个天然难点:
- 类别极度不平衡:本数据集中欺诈交易只占
0.1727%,如果模型无脑预测“正常”,准确率也能高达 99.8% 以上,但没有任何实际意义。 - 代价不对称:漏掉一笔欺诈(召回率低)和误伤一笔正常交易(精确率低)都会造成损失,所以不能只看准确率,需要综合评估。
本项目的目标就是:
- 通过 EDA 了解数据分布;
- 用 SMOTE 缓解类别不平衡;
- 训练多个模型并对比评估;
- 找到兼顾精确率与召回率的最佳模型;
- 通过阈值调优进一步提升 F1 分数;
- 分析模型最重要的特征。
二、环境准备
2.1 安装 Python 与依赖
建议使用 Python 3.9 及以上版本。你可以直接使用 Anaconda,也可以使用系统自带的 Python。
1 | pip install pandas numpy matplotlib seaborn scikit-learn imbalanced-learn |
需要说明的是,imbalanced-learn 是专门用来处理不平衡数据集的库,本项目主要使用其中的 SMOTE。
2.2 下载数据集
数据集来自 Kaggle:Credit Card Fraud Detection。
- 数据文件:
creditcard.csv - 大小:约 150 MB
- 下载地址:https://www.kaggle.com/datasets/mlg-ulb/creditcardfraud
下载后把 creditcard.csv 放在项目根目录即可。
2.3 项目目录结构
1 | Creditcard_Fraud_Project/ |
三、项目结构与整体流程
整个项目的代码都写在一个主脚本 Creditcard_Fraud.py 中,逻辑清晰,可以分为 7 个阶段:
1 | 读取数据 |
下面我们按顺序讲解每一段代码。
四、分步代码讲解
4.1 导入库与中文显示设置
1 | import numpy as np |
这里的重点有两个:
imblearn.over_sampling.SMOTE用于后续的过采样;plt.rcParams设置中文字体,否则图表里的中文会变成方框。
4.2 读取数据
1 | data = pd.read_csv('creditcard.csv') |
X 是所有特征,y 是标签。Class = 1 表示欺诈交易,Class = 0 表示正常交易。
4.3 EDA:探索性数据分析
1 | print(X.info()) |
数据类型检查
运行 X.info() 可以看到:
1 | RangeIndex: 284807 entries, 0 to 284806 |
也就是说数据集一共有 284807 条交易记录,30 个特征全部是 float64 类型,没有缺失值。y 是 int64 类型,也没有缺失值。


类别分布
1 | 欺诈样本占比: 0.1727% |
对应到具体数量:
- 正常交易:
284315条 - 欺诈交易:
492条
欺诈样本只有 492 条,这是一个非常典型的高度不平衡数据集。
金额分布

从图中可以看出:
- 正常交易的金额分布较广,大部分金额集中在较小的区间;
- 欺诈交易的金额明显偏小,大部分欺诈交易金额集中在 0 到几百美元之间。
这说明 Amount 特征对欺诈识别有一定区分度,因此后续需要单独做标准化。
4.4 划分数据集与标准化
1 | X_train, X_test, y_train, y_test = train_test_split( |
这里有两个关键设计:
分层抽样
stratify=y:因为欺诈样本太少,如果不分层,随机划分很可能把欺诈样本全部切到训练集或测试集。分层抽样保证训练集和测试集中的正负样本比例与原始数据一致。本项目的划分结果是:- 训练集:
227845条 - 测试集:
56962条(其中欺诈样本98条)
- 训练集:
只对
Time和Amount标准化:V1 - V28已经是 PCA 降维后的匿名特征,数值范围本身比较规整;而Time(交易时间)和Amount(金额)量纲差异大,不标准化会影响距离类模型(如 KNN、逻辑回归)的效果。
4.5 SMOTE 数据增强
1 | smote = SMOTE(random_state=42, sampling_strategy='auto') |
SMOTE(Synthetic Minority Over-sampling Technique)的核心思想是:
对少数类样本(欺诈样本),在其近邻样本之间通过插值合成新的少数类样本,而不是简单复制。
这样处理后,训练集中的正常样本和欺诈样本数量会变成一样多(各 227451 条,共 454902 条)。
需要注意两点:
- 只在训练集上做 SMOTE:测试集必须保持真实分布,否则评估结果会失真;
- 同时保留原始训练数据:代码用
X_train_original, y_train_original保存了一份,用于后续对比“SMOTE 前后”的召回率变化。
4.6 模型训练循环
1 | model_dict = { |
本项目对比了 5 个经典模型:
| 模型 | 说明 |
|---|---|
| Logistic Regression | 线性模型,训练快,适合做基线 |
| Decision Tree | 单棵决策树,容易过拟合 |
| Random Forest | 随机森林,100 棵树,集成学习 |
| Gradient Boosting | 梯度提升树,默认参数 |
| KNN | K 近邻,k=5 |
代码里还做了两件容易被忽略但很重要的事:
- 每个模型都在原始数据上训练一次,得到“SMOTE 之前的召回率”,用于量化数据增强的效果;
- 每个模型在 SMOTE 数据上做 5 折分层交叉验证,打印
CV F1,避免单次划分的偶然性。
原代码中还有 SVM 和单独的逻辑回归练习块,因为训练耗时太长,被注释掉了,不影响主流程。
4.7 评估指标
在欺诈检测场景中,最常用的指标是:
| 指标 | 含义 | 公式 |
|---|---|---|
| Accuracy | 所有样本中预测正确的比例 | (TP + TN) / (TP + FP + FN + TN) |
| Precision | 预测为欺诈的交易中,真的是欺诈的比例 | TP / (TP + FP) |
| Recall | 真实欺诈交易中被成功找出的比例 | TP / (TP + FN) |
| F1-Score | 精确率与召回率的调和平均 | 2PR / (P + R) |
| ROC-AUC | 模型排序能力的综合指标,越接近 1 越好 | 由 TPR 与 FPR 曲线下面积计算 |
为什么不能只看 Accuracy?
因为欺诈占比只有 0.1727%,模型全部预测为“正常”也能得到 99.8% 的准确率,但一个欺诈都找不出来。所以在不平衡场景下,重点看 Recall(别漏掉欺诈) 和 F1(精确率与召回率的平衡)。
4.8 模型对比可视化
4.8.1 性能指标柱状图

这张图把所有模型的 Accuracy、Precision、Recall、F1-Score、ROC-AUC 放在一起对比,可以直观看到:几乎所有模型 Accuracy 都接近 1,但 Precision 和 Recall 差异巨大,说明只看准确率没有意义。
4.8.2 最佳模型混淆矩阵
按 F1-Score 排序,本项目的前三名是:
- Random Forest:
0.8410 - KNN:
0.6078 - Decision Tree:
0.4735

随机森林的归一化混淆矩阵显示:正常交易中 99.97% 被正确识别,欺诈交易中 83.67% 被正确识别,只有 16.33% 的欺诈被漏掉。
4.8.3 ROC 曲线对比

Top 3 模型的 ROC 曲线中,随机森林的 AUC 最高(0.9731),说明模型对“欺诈 vs 正常”的排序能力最好。
4.8.4 Precision-Recall 曲线对比

PR 曲线越靠近右上角越好。随机森林在召回率较高时仍然保持了不错的精确率,因此曲线位置最优。
4.8.5 Top 5 模型雷达图

雷达图用 Precision、Recall、F1-Score、ROC-AUC 四个维度评估模型,随机森林在四个维度上都很均衡,面积最大。
4.8.6 SMOTE 前后召回率对比

这是本项目最有意思的一张图。SMOTE 对每个模型的召回率提升效果如下:
| 模型 | 原始数据 Recall | SMOTE 后 Recall | 提升 |
|---|---|---|---|
| Logistic Regression | 0.6429 | 0.9184 | +27.6 个百分点 |
| Decision Tree | 0.7449 | 0.7755 | +3.1 个百分点 |
| Random Forest | 0.8163 | 0.8367 | +2.0 个百分点 |
| Gradient Boosting | 0.1837 | 0.8980 | +71.4 个百分点 |
| KNN | 0.8061 | 0.8776 | +7.2 个百分点 |
可以看到:
- 梯度提升提升最明显(+71.4 个百分点),说明原始不平衡数据让它“完全不敢预测欺诈”;
- 随机森林本身在原始数据上召回率就比较高(0.8163),SMOTE 仍然带来了小幅提升。
4.9 最佳模型分析与阈值调优
4.9.1 随机森林的分类报告
1 | best_model_name = max(results['F1-Score'].items(), key=lambda x: x[1])[0] |

随机森林的分类报告:
1 | precision recall f1-score support |
4.9.2 为什么还要调阈值?
sklearn 默认把 predict_proba 输出概率 >= 0.5 判为欺诈。但这个 0.5 只是数学上的默认值,并不是业务上的最优值。
在欺诈检测中,我们可以调整阈值,在“多抓欺诈但多误报”和“少误报但漏欺诈”之间做选择。本项目通过 PR 曲线自动搜索 F1 最高的阈值:
1 | precision, recall, thresholds = precision_recall_curve(y_test, y_proba_best) |

调优结果:
| 指标 | 默认阈值 0.5 | 最优阈值 0.77 | 变化 |
|---|---|---|---|
| Precision | 0.8454 | 0.9620 | +11.7 个百分点 |
| Recall | 0.8367 | 0.7755 | -6.1 个百分点 |
| F1-Score | 0.8410 | 0.8588 | +1.8 个百分点 |
也就是说,把阈值提高到 0.77 后:
- 精确率大幅提升(预测为欺诈的交易更可信了);
- 召回率小幅下降(会漏掉略多一点的欺诈);
- 整体 F1 从
0.8410提升到0.8588。
实际业务中阈值怎么选,取决于“误报一笔正常交易”和“漏掉一笔欺诈”哪个成本更高。如果想提高召回率,就降低阈值;想提高精确率,就提高阈值。
4.10 特征重要性分析
随机森林是树模型,自带特征重要性。代码如下:
1 | importance_df = pd.DataFrame({ |


Top 15 特征及重要性:
| 排名 | 特征 | 重要性 |
|---|---|---|
| 1 | V14 | 0.1956 |
| 2 | V10 | 0.1105 |
| 3 | V4 | 0.1061 |
| 4 | V12 | 0.0951 |
| 5 | V17 | 0.0850 |
| 6 | V3 | 0.0605 |
| 7 | V11 | 0.0564 |
| 8 | V16 | 0.0438 |
| 9 | V2 | 0.0370 |
| 10 | V9 | 0.0262 |
| 11 | V7 | 0.0185 |
| 12 | V21 | 0.0159 |
| 13 | V8 | 0.0157 |
| 14 | V18 | 0.0139 |
| 15 | V27 | 0.0112 |
V14 的重要性最高(0.1956),V10、V4、V12 紧随其后。由于这些特征是 PCA 降维后的匿名特征,我们无法直接知道它们对应什么业务含义,但可以做特征选择实验:例如只用 Top 10 特征重新训练,往往也能保持接近的 F1。
4.11 为什么最终选择随机森林?
项目最后从三个角度论证模型选择:



- F1-Score 排名第一:随机森林
0.8410,明显高于第二名 KNN 的0.6078。 - PR 曲线位置最优:在相同召回率下,随机森林能保持更高的精确率。
- 综合评分最高:以
(F1 + ROC-AUC) / 2作为综合评分,随机森林得到0.9071,是所有模型中最高的。
五、复现结果汇总
如果你完整跑完一遍,应该能得到下面的结果表(本机实测):
| 模型 | Accuracy | Precision | Recall | F1-Score | ROC-AUC |
|---|---|---|---|---|---|
| Logistic Regression | 0.9742 | 0.0580 | 0.9184 | 0.1092 | 0.9699 |
| Decision Tree | 0.9970 | 0.3408 | 0.7755 | 0.4735 | 0.8865 |
| Random Forest | 0.9995 | 0.8454 | 0.8367 | 0.8410 | 0.9731 |
| Gradient Boosting | 0.9867 | 0.1055 | 0.8980 | 0.1888 | 0.9807 |
| KNN | 0.9981 | 0.4649 | 0.8776 | 0.6078 | 0.9536 |
结论:
- 随机森林在精确率与召回率之间取得了最佳平衡,是最终选定的模型;
- SMOTE 显著提升了所有模型的召回率,尤其是梯度提升(+71.4 个百分点);
- 阈值调优让随机森林的 F1 从
0.8410提升到0.8588; V14、V10、V4是最重要的三个特征。
六、常见问题
1. 运行很久怎么办?
项目里最耗时的是梯度提升、KNN 和随机森林的 5 折交叉验证。可以先把 model_dict 中的模型删到只剩 2 个,或者把 cross_val_score 的 cv 从 5 改成 3。也可以安装 scikit-learn-intelex 加速。
2. 中文显示成方框怎么办?
说明系统没有 SimHei 字体。可以把代码第一行改成:
1 | plt.rcParams['font.sans-serif'] = ['Microsoft YaHei'] |
3. 为什么逻辑回归精确率那么低?
SMOTE 把训练集变得完全平衡后,逻辑回归会倾向于把更多交易预测为欺诈(在测试集上多误报了 1461 笔正常交易),所以召回率上去了、精确率掉下来了。这说明“过采样”不是免费的,需要在精确率和召回率之间做权衡。
4. SVM 为什么被注释掉了?
默认参数的 SVM 在 22 万条样本上训练非常慢,代码里已经注释掉,不影响复现。
5. 为什么测试集是 56962 条而不是整数?
train_test_split(test_size=0.2) 在分层抽样时按类别比例分配,正常类测试集为 56864 条,欺诈类测试集为 98 条,合计 56962 条。
七、总结与改进方向
这个项目完整走完了一个机器学习二分类任务的闭环:数据探索 → 不平衡处理 → 多模型对比 → 评估 → 调优 → 特征分析。从中可以学到的核心经验是:
- 不平衡数据下不能只看 Accuracy,要看 Precision、Recall、F1 和 ROC-AUC;
- SMOTE 能有效提升召回率,但要注意精确率的代价;
- 默认阈值 0.5 不是最优的,结合业务用 PR 曲线调阈值非常实用;
- 树模型(随机森林)在表格型数据上通常有很好的表现,而且自带特征重要性。
如果想继续深入,可以从这些方向改进:
- 尝试 XGBoost、LightGBM、CatBoost;
- 对比 SMOTE、ADASYN、Tomek Links、NearMiss 等采样策略;
- 用 SHAP 做可解释性分析;
- 引入业务成本函数,把“漏报/误报”的损失直接写进模型优化目标;
- 把模型封装成 API,接入实时风控系统。
如果你按照本文成功复现了项目,欢迎在评论区分享你的模型结果,看看不同硬件和依赖版本下指标是否一致。
