memily0/fraud-detection-ml-system
GitHub: memily0/fraud-detection-ml-system
一个端到端的机器学习欺诈检测系统,使用 FastAPI 提供服务,并以可复现流程解决类别不平衡下的交易风险预测问题。
Stars: 1 | Forks: 0
# 欺诈检测 ML 系统
一个用于评估欺诈交易概率的端到端 ML/backend 教学项目。
这是一个可复现的欺诈检测项目,包含训练 pipeline、用于训练和推理的共享特征工程、FastAPI API、演示 dashboard,以及用于本地启动的 Docker 配置。
## 概述
| 项目 | 详情 |
| --- | --- |
| 任务 | 用于欺诈检测的二元分类 |
| 数据集 | `data/creditcard.csv` |
| 模型 | `RandomForestClassifier` |
| API | FastAPI (`/predict`, `/health`) |
| Dashboard | 位于 `/dashboard/` 的静态 Web UI |
| Docker | `Dockerfile` + `docker-compose.yml` |
最终提供服务的模型:`RandomForestClassifier`,它是通过分阶段的模型比较(包含单次划分 baseline、分层交叉验证和独立的阈值调优)筛选出来的。
**最终提供服务的模型:** `RandomForestClassifier`,通过分阶段比较模型选出。
## 技术栈
- Python
- pandas
- NumPy
- scikit-learn
- CatBoost
- joblib
- FastAPI
- Pydantic
- Uvicorn
- Docker
## 项目组件
## 项目组件 / 项目包含内容
- 源自 `data/creditcard.csv` 的可复现训练 pipeline
(可复现的训练 pipeline)
- 用于训练和推理的共享特征工程
(统一的特征逻辑用于 train 和 inference)
- 用于欺诈评分的 RandomForest 服务模型
(用于 fraud 评分的主要模型)
- 保留 CatBoost baseline 用于模型比较
(CatBoost 作为强有力的 baseline 候选模型保留)
- 在分层测试集上进行评估
- 用于预测的 FastAPI 服务
- 用于手动推理检查的简单 dashboard
- 用于本地演示启动的 Docker 配置
## 指标
当前主要训练 pipeline 在测试集上的指标:
**以下是当前服务模型在 test split 上的主要指标。**
| 指标 | 数值 |
| --- | ---: |
| PR-AUC | 0.876845 |
| ROC-AUC | 0.967647 |
| F2 | 0.788913 |
| Precision | 0.961039 |
| Recall | 0.755102 |
| 阈值 | 0.50 |
这些是主要 train/test pipeline 在 `threshold = 0.5` 时的默认评估指标。
最终 `RandomForestClassifier` 调整后的运行阈值在 **模型选择** 部分单独报告,目前为 `0.2`。
为什么这些指标很重要 / 为什么这些指标很重要:
- 对于此数据集,`PR-AUC` 比准确率提供更多信息,因为欺诈案例很罕见。
(由于严重的类不平衡,`PR-AUC` 比准确率更重要。)
- `Recall` 很重要,因为漏掉欺诈交易的代价很高。
(`Recall` 很重要,因为漏掉 fraud 操作代价高昂。)
- `F2` 给予 recall 更高的权重,这比对称指标更适合欺诈检测场景。
(`F2` 更加强调 recall。)
## 快速开始
最简本地流程:
```
python3 -m venv .venv
source .venv/bin/activate
pip install -r requirements.txt
python scripts/train_model.py
uvicorn app.main:app --reload
```
启动后:
- Dashboard:`http://localhost:8000/dashboard/`
- 健康检查:`http://localhost:8000/health`
- API 文档:`http://localhost:8000/docs`
## 问题背景
该项目将欺诈检测视为一个二元分类任务:对于每笔交易,模型预测其属于欺诈类别的概率。
数据集包含:
- `Time`
- `Amount`
- `V1` ... `V28`
- `Class` 作为目标
为什么该任务不简单:
- 数据集严重不平衡,欺诈交易只占极小的比例;
- API 处理的是数据集中转换后的特征空间,而不是原始的业务交易字段;
- 由于不平衡,高准确率并不一定意味着模型是有用的。
## ML Pipeline
当前 pipeline:
1. 从 `data/creditcard.csv` 加载数据
2. 构建最终的特征集
3. 使用分层抽样将数据划分为 train/test
4. 训练 `RandomForestClassifier`
5. 在 test split 上进行评估
6. 将训练好的模型保存到 `models/random_forest_fraud_model.joblib`
7. 在 FastAPI 中加载保存的模型并在 `/predict` 中使用
服务产出物是一个序列化的 sklearn `Pipeline`。它包含拟合好的 `RandomForestClassifier` 和服务所需的预处理步骤,包括针对 `time_bin` 的 one-hot 编码。
当前模型参数:
- `n_estimators=200`
- `class_weight='balanced'`
- `n_jobs=-1`
- `random_state=42`
## 模型选择 / 最终模型如何选出
该项目采用了流程驱动的模型选择方法。
**这里的模型选择是作为一个独立的、深思熟虑的过程进行的,而不是通过单次运行就做出的决定。**
本项目中的模型选择是分阶段进行的,而不是仅仅依靠直觉。
1. **单次划分基准测试** 被用作在一个分层 train/test 划分上的快速初步 baseline。
2. **分层交叉验证基准测试** 成为了主要的模型选择程序。
3. 使用跨 CV 折叠的 `mean PR-AUC` 作为主要选择指标,因为欺诈类别严重不平衡。
4. 在候选名单确定后,使用 `F2` 在单独的验证集上独立进行 **阈值调优**。
5. 基于此过程,选择 `RandomForestClassifier` 作为最终的服务模型。
模型选择总结 / 简要说明:
- 单次划分基准测试作为快速的 baseline 比较;
- 交叉验证基准测试是模型选择的主要来源;
- `CatBoostClassifier` 作为强有力的基准候选保留在代码库中,而不是作为最终的服务模型。
- 单次划分基准测试作为快速 baseline 保留;
- CV 基准测试作为模型选择的主要阶段;
- `CatBoostClassifier` 在项目中作为强有力的候选者保留,但不是最终的服务模型。
交叉验证基准测试总结:
| 模型 | 平均 PR-AUC | PR-AUC 标准差 | 平均 ROC-AUC | ROC-AUC 标准差 |
| --- | ---: | ---: | ---: | ---: |
| RandomForestClassifier | 0.855822 | 0.024644 | 0.954049 | 0.010747 |
| CatBoostClassifier | 0.811840 | 0.038346 | 0.981338 | 0.001592 |
| LogisticRegression | 0.760740 | 0.014065 | 0.977431 | 0.007064 |
候选模型的阈值调优:
| 模型 | 阈值 | 精确率 | 召回率 | F2 |
| --- | ---: | ---: | ---: | ---: |
| RandomForestClassifier | 0.2 | 0.924731 | 0.877551 | 0.886598 |
| CatBoostClassifier | 0.9 | 0.833333 | 0.867347 | 0.860324 |
此阈值分析有意与模型选择分开:
- 模型选择基于交叉验证的 `mean PR-AUC`;
- 运行阈值选择基于候选模型在单独验证集上的 `F2` 分数;
- 对于最终的服务模型,调整后的运行阈值为 `0.2`,而上述主要的训练指标仍以默认的 `0.5` 进行报告。
## 特征工程 / 特征构建
该模型使用 33 个特征。
基础特征:
- `Time`
- `Amount`
- `V1` ... `V28`
派生特征:
- `hour` — 从 `Time` 中提取,用于捕捉日内时间规律
- `log_amount` — `log1p(Amount)`,以减少长尾金额分布的影响
- `time_bin` — 分类时间桶:`night`、`morning`、`afternoon`、`evening`
重要细节 / 重要细节:
- 相同的特征工程逻辑在训练和推理中都被重用,因此训练和服务保持一致。
- 在训练和推理中都使用了相同的特征逻辑,因此不会出现训练/推理不匹配的情况。
## API
### `GET /`
重定向到 dashboard:
- `http://localhost:8000/` -> `http://localhost:8000/dashboard/`
### `GET /health`
返回服务状态:
```
{
"status": "ok"
}
```
### `POST /predict`
接受数据集特征格式的一笔交易,并返回欺诈概率。
响应示例:
```
{
"fraud_proba": 0.39
}
```
注意事项:
- API 期望与数据集相同的特征 schema;
- 这对于演示 ML pipeline 很有用,但它并不是用于生产反欺诈服务的真实公共接口。
## Dashboard
该代码库在 `/dashboard/` 中包含一个简单的 Web UI。
它允许你:
- 手动输入交易特征;
- 加载样本交易;
- 向 `/predict` 发送请求;
- 在轻量级界面中检查返回的欺诈概率。
此 dashboard 旨在用于演示和手动验证,而不是用于分析或运维工作。
## 项目结构
```
fraud-detection-ml-system/
├── README.md
├── Dockerfile
├── docker-compose.yml
├── requirements.txt
├── app/
│ ├── main.py
│ └── utils.py
├── dashboard/
│ ├── index.html
│ ├── app.js
│ └── styles.css
├── data/
│ └── creditcard.csv
├── models/
│ ├── catboost_fraud_model.cbm
│ └── random_forest_fraud_model.joblib
├── scripts/
│ ├── compare_models.py
│ ├── compare_models_cv.py
│ └── train_model.py
└── src/
├── features/
│ └── fraud_features.py
├── inference/
│ └── predict.py
├── models/
│ └── model_utils.py
├── training/
│ ├── compare_models.py
│ ├── compare_models_cv.py
│ └── train.py
└── utils/
└── metrics.py
```
关键文件:
- `src/features/fraud_features.py` — 共享特征工程
- `src/training/train.py` — 训练、划分、评估、模型保存
- `src/training/compare_models.py` — 单次划分基准测试
- `src/training/compare_models_cv.py` — 基于 CV 的模型选择和阈值调优
- `scripts/train_model.py` — 用于模型训练的 CLI 入口点
- `app/main.py` — FastAPI 应用和端点
- `models/random_forest_fraud_model.joblib` — 作为序列化 sklearn pipeline 的主要服务产出物
- `models/catboost_fraud_model.cbm` — 保留的基准产出物
## 在本地运行
1. 创建并激活虚拟环境:
```
python3 -m venv .venv
source .venv/bin/activate
```
2. 安装依赖:
```
pip install -r requirements.txt
```
3. 确保数据集存在于 `data/creditcard.csv`
4. 训练模型:
```
python scripts/train_model.py
```
可选参数:
```
python scripts/train_model.py \
--data-path data/creditcard.csv \
--model-path models/random_forest_fraud_model.joblib \
--test-size 0.2 \
--random-state 42 \
--threshold 0.5
```
5. 启动 API:
```
uvicorn app.main:app --reload
```
## 使用 Docker 运行
在使用 Docker 之前,模型应该已经存在于 `models/random_forest_fraud_model.joblib` 中,因为容器会使用现成的模型产出物启动 API。
构建并运行:
```
docker compose up --build
```
启动后:
- `http://localhost:8000/dashboard/`
- `http://localhost:8000/health`
- `http://localhost:8000/docs`
当前的 Docker 限制:
- 此设置旨在用于本地演示,并且仍然将 `models/` 和 `data/` 都复制到容器中。
## 限制 / 限制
- 这是一个学习/演示项目,不是生产部署;
- API 期望接收 PCA 风格的数据集特征 `V1` ... `V28`,而不是原始交易字段;
- 主要的训练指标仍然基于单次分层 train/test 划分进行报告;
- 该项目确实包含 CV 基准测试和阈值调优,但不包含重复 CV、嵌套验证或超参数搜索;
- 没有实验跟踪;
- 目前还没有针对训练 pipeline 或 API 的自动化测试;
- 没有生产级别的日志记录、监控或部署设置;
- dashboard 有意保持轻量级,并不是一个完整的分析工具;
- 模型选择比以前更稳健,但仍然没有完整的实验管理工作流作为后盾。
## 未来改进
- 基于业务权衡进行阈值调优
- 针对特征工程、训练和 `/predict` 进行测试
- 用于模型和 pipeline 参数的配置/设置
- 基本的 API 日志记录和错误报告
- 更丰富的 dashboard 解释
- 保存的指标报告和简短的模型卡片
## 展示的技能 / 该项目展示的内容
- 针对不平衡分类的表格 ML
- 可复现的模型训练 pipeline
- 通过 baseline 基准测试、CV 基准测试和阈值调优进行的流程驱动模型选择
- 用于训练和推理的共享特征工程
- 用于模型推理的 FastAPI 服务
- 使用 Docker 进行模型打包和本地部署
- 端到端地展示 ML 项目,以供作品集和面试讨论
- 处理表格数据和严重的类不平衡
- 可复现的训练 pipeline
- 通过基准测试 + CV + 阈值调优进行深思熟虑的模型选择
- 保持训练和推理一致
- 通过 FastAPI 提供 ML 服务
- 将项目打包到 Docker 中
请求 payload 示例
``` { "Time": 0.0, "Amount": 149.62, "V1": -1.3598071336738, "V2": -0.0727811733098497, "V3": 2.53634673796914, "V4": 1.37815522427443, "V5": -0.338320769942518, "V6": 0.462387777762292, "V7": 0.239598554061257, "V8": 0.0986979012610507, "V9": 0.363786969611213, "V10": 0.0907941719789316, "V11": -0.551599533260813, "V12": -0.617800855762348, "V13": -0.991389847235408, "V14": -0.311169353699879, "V15": 1.46817697209427, "V16": -0.470400525259478, "V17": 0.207971241929242, "V18": 0.0257905801985591, "V19": 0.403992960255733, "V20": 0.251412098239705, "V21": -0.018306777944153, "V22": 0.277837575558899, "V23": -0.110473910188767, "V24": 0.0669280749146731, "V25": 0.128539358273528, "V26": -0.189114843888824, "V27": 0.133558376740387, "V28": -0.0210530534538215 } ```标签:Apex, AV绕过, CatBoost, Docker, FastAPI, Scikit-learn, 安全防御评估, 机器学习, 欺诈检测