项目二教学文档:信用卡欺诈检测 ------ 不平衡分类
https://gitee.com/ghaweiuptgb/machine-learning-AI.git (代码包)
使用说明 :本文档是项目二的完整教学记录。每完成一个步骤,我会把该步骤的详细教学过程写入对应章节。
配套文件:
- 总体规划见
../机器学习实战学习路线.md- 你的个人笔记写在
README.md- 代码写在
src/train.py代码规范 :逐行注释 + 图表中文(见根目录
.cursor/rules/)讲解规范 :详细讲解 + 新名词必解释 + Mermaid 图解 + 每步提供动手任务与验收标准参考答案
目录
| 步骤 | 标题 | 状态 |
|---|---|---|
| [步骤 1](#步骤 标题 状态 步骤 1 环境与子项目初始化 ✅ 已完成教学 步骤 2 EDA 与不平衡认知 ✅ 已完成教学 步骤 3 划分数据 —— 分层抽样 ✅ 已完成教学 步骤 4 基准模型 Logistic Regression ✅ 已完成教学 步骤 5 使用 class_weight 平衡 ✅ 已完成教学 步骤 6 SMOTE 过采样(仅训练集) ✅ 已完成教学 步骤 7 换用树模型 Random Forest ✅ 已完成教学 步骤 8 阈值调优 ✅ 已完成教学 步骤 9 项目总结 ✅ 已完成教学) | 环境与子项目初始化 | ✅ 已完成教学 |
| [步骤 2](#步骤 标题 状态 步骤 1 环境与子项目初始化 ✅ 已完成教学 步骤 2 EDA 与不平衡认知 ✅ 已完成教学 步骤 3 划分数据 —— 分层抽样 ✅ 已完成教学 步骤 4 基准模型 Logistic Regression ✅ 已完成教学 步骤 5 使用 class_weight 平衡 ✅ 已完成教学 步骤 6 SMOTE 过采样(仅训练集) ✅ 已完成教学 步骤 7 换用树模型 Random Forest ✅ 已完成教学 步骤 8 阈值调优 ✅ 已完成教学 步骤 9 项目总结 ✅ 已完成教学) | EDA 与不平衡认知 | ✅ 已完成教学 |
| [步骤 3](#步骤 标题 状态 步骤 1 环境与子项目初始化 ✅ 已完成教学 步骤 2 EDA 与不平衡认知 ✅ 已完成教学 步骤 3 划分数据 —— 分层抽样 ✅ 已完成教学 步骤 4 基准模型 Logistic Regression ✅ 已完成教学 步骤 5 使用 class_weight 平衡 ✅ 已完成教学 步骤 6 SMOTE 过采样(仅训练集) ✅ 已完成教学 步骤 7 换用树模型 Random Forest ✅ 已完成教学 步骤 8 阈值调优 ✅ 已完成教学 步骤 9 项目总结 ✅ 已完成教学) | 划分数据 ------ 分层抽样 | ✅ 已完成教学 |
| [步骤 4](#步骤 标题 状态 步骤 1 环境与子项目初始化 ✅ 已完成教学 步骤 2 EDA 与不平衡认知 ✅ 已完成教学 步骤 3 划分数据 —— 分层抽样 ✅ 已完成教学 步骤 4 基准模型 Logistic Regression ✅ 已完成教学 步骤 5 使用 class_weight 平衡 ✅ 已完成教学 步骤 6 SMOTE 过采样(仅训练集) ✅ 已完成教学 步骤 7 换用树模型 Random Forest ✅ 已完成教学 步骤 8 阈值调优 ✅ 已完成教学 步骤 9 项目总结 ✅ 已完成教学) | 基准模型 Logistic Regression | ✅ 已完成教学 |
| [步骤 5](#步骤 标题 状态 步骤 1 环境与子项目初始化 ✅ 已完成教学 步骤 2 EDA 与不平衡认知 ✅ 已完成教学 步骤 3 划分数据 —— 分层抽样 ✅ 已完成教学 步骤 4 基准模型 Logistic Regression ✅ 已完成教学 步骤 5 使用 class_weight 平衡 ✅ 已完成教学 步骤 6 SMOTE 过采样(仅训练集) ✅ 已完成教学 步骤 7 换用树模型 Random Forest ✅ 已完成教学 步骤 8 阈值调优 ✅ 已完成教学 步骤 9 项目总结 ✅ 已完成教学) | 使用 class_weight 平衡 | ✅ 已完成教学 |
| [步骤 6](#步骤 标题 状态 步骤 1 环境与子项目初始化 ✅ 已完成教学 步骤 2 EDA 与不平衡认知 ✅ 已完成教学 步骤 3 划分数据 —— 分层抽样 ✅ 已完成教学 步骤 4 基准模型 Logistic Regression ✅ 已完成教学 步骤 5 使用 class_weight 平衡 ✅ 已完成教学 步骤 6 SMOTE 过采样(仅训练集) ✅ 已完成教学 步骤 7 换用树模型 Random Forest ✅ 已完成教学 步骤 8 阈值调优 ✅ 已完成教学 步骤 9 项目总结 ✅ 已完成教学) | SMOTE 过采样(仅训练集) | ✅ 已完成教学 |
| [步骤 7](#步骤 标题 状态 步骤 1 环境与子项目初始化 ✅ 已完成教学 步骤 2 EDA 与不平衡认知 ✅ 已完成教学 步骤 3 划分数据 —— 分层抽样 ✅ 已完成教学 步骤 4 基准模型 Logistic Regression ✅ 已完成教学 步骤 5 使用 class_weight 平衡 ✅ 已完成教学 步骤 6 SMOTE 过采样(仅训练集) ✅ 已完成教学 步骤 7 换用树模型 Random Forest ✅ 已完成教学 步骤 8 阈值调优 ✅ 已完成教学 步骤 9 项目总结 ✅ 已完成教学) | 换用树模型 Random Forest | ✅ 已完成教学 |
| [步骤 8](#步骤 标题 状态 步骤 1 环境与子项目初始化 ✅ 已完成教学 步骤 2 EDA 与不平衡认知 ✅ 已完成教学 步骤 3 划分数据 —— 分层抽样 ✅ 已完成教学 步骤 4 基准模型 Logistic Regression ✅ 已完成教学 步骤 5 使用 class_weight 平衡 ✅ 已完成教学 步骤 6 SMOTE 过采样(仅训练集) ✅ 已完成教学 步骤 7 换用树模型 Random Forest ✅ 已完成教学 步骤 8 阈值调优 ✅ 已完成教学 步骤 9 项目总结 ✅ 已完成教学) | 阈值调优 | ✅ 已完成教学 |
| [步骤 9](#步骤 标题 状态 步骤 1 环境与子项目初始化 ✅ 已完成教学 步骤 2 EDA 与不平衡认知 ✅ 已完成教学 步骤 3 划分数据 —— 分层抽样 ✅ 已完成教学 步骤 4 基准模型 Logistic Regression ✅ 已完成教学 步骤 5 使用 class_weight 平衡 ✅ 已完成教学 步骤 6 SMOTE 过采样(仅训练集) ✅ 已完成教学 步骤 7 换用树模型 Random Forest ✅ 已完成教学 步骤 8 阈值调优 ✅ 已完成教学 步骤 9 项目总结 ✅ 已完成教学) | 项目总结 | ✅ 已完成教学 |
步骤 1:环境与子项目初始化
状态 :✅ 已完成教学(数据已下载至
data/creditcard.csv)
1.1 本步目标
- 创建
project_02_fraud/目录结构(与项目一一致) - 下载并加载 Credit Card Fraud Detection 数据集
- 安装
imbalanced-learn(后续 SMOTE 需要) - 运行
train.py,确认能打印前 5 行
1.2 这一步在解决什么问题?
项目一学的是回归 (预测连续房价)。项目二进入分类 (预测正常/欺诈),且面临一个新挑战:类别极度不平衡 ------欺诈交易只占约 0.17%。
在写任何模型之前,必须先:
- 搭好项目「工地」(目录、脚本、依赖)
- 把数据放到固定位置
data/creditcard.csv - 确认环境能正常
read_csv
1.3 本步在整体流程中的位置
#mermaid-svg-7GYoK8eV0LDuC7Nv{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-7GYoK8eV0LDuC7Nv .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-7GYoK8eV0LDuC7Nv .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-7GYoK8eV0LDuC7Nv .error-icon{fill:#552222;}#mermaid-svg-7GYoK8eV0LDuC7Nv .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-7GYoK8eV0LDuC7Nv .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-7GYoK8eV0LDuC7Nv .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-7GYoK8eV0LDuC7Nv .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-7GYoK8eV0LDuC7Nv .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-7GYoK8eV0LDuC7Nv .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-7GYoK8eV0LDuC7Nv .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-7GYoK8eV0LDuC7Nv .marker{fill:#333333;stroke:#333333;}#mermaid-svg-7GYoK8eV0LDuC7Nv .marker.cross{stroke:#333333;}#mermaid-svg-7GYoK8eV0LDuC7Nv svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-7GYoK8eV0LDuC7Nv p{margin:0;}#mermaid-svg-7GYoK8eV0LDuC7Nv .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-7GYoK8eV0LDuC7Nv .cluster-label text{fill:#333;}#mermaid-svg-7GYoK8eV0LDuC7Nv .cluster-label span{color:#333;}#mermaid-svg-7GYoK8eV0LDuC7Nv .cluster-label span p{background-color:transparent;}#mermaid-svg-7GYoK8eV0LDuC7Nv .label text,#mermaid-svg-7GYoK8eV0LDuC7Nv span{fill:#333;color:#333;}#mermaid-svg-7GYoK8eV0LDuC7Nv .node rect,#mermaid-svg-7GYoK8eV0LDuC7Nv .node circle,#mermaid-svg-7GYoK8eV0LDuC7Nv .node ellipse,#mermaid-svg-7GYoK8eV0LDuC7Nv .node polygon,#mermaid-svg-7GYoK8eV0LDuC7Nv .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-7GYoK8eV0LDuC7Nv .rough-node .label text,#mermaid-svg-7GYoK8eV0LDuC7Nv .node .label text,#mermaid-svg-7GYoK8eV0LDuC7Nv .image-shape .label,#mermaid-svg-7GYoK8eV0LDuC7Nv .icon-shape .label{text-anchor:middle;}#mermaid-svg-7GYoK8eV0LDuC7Nv .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-7GYoK8eV0LDuC7Nv .rough-node .label,#mermaid-svg-7GYoK8eV0LDuC7Nv .node .label,#mermaid-svg-7GYoK8eV0LDuC7Nv .image-shape .label,#mermaid-svg-7GYoK8eV0LDuC7Nv .icon-shape .label{text-align:center;}#mermaid-svg-7GYoK8eV0LDuC7Nv .node.clickable{cursor:pointer;}#mermaid-svg-7GYoK8eV0LDuC7Nv .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-7GYoK8eV0LDuC7Nv .arrowheadPath{fill:#333333;}#mermaid-svg-7GYoK8eV0LDuC7Nv .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-7GYoK8eV0LDuC7Nv .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-7GYoK8eV0LDuC7Nv .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-7GYoK8eV0LDuC7Nv .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-7GYoK8eV0LDuC7Nv .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-7GYoK8eV0LDuC7Nv .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-7GYoK8eV0LDuC7Nv .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-7GYoK8eV0LDuC7Nv .cluster text{fill:#333;}#mermaid-svg-7GYoK8eV0LDuC7Nv .cluster span{color:#333;}#mermaid-svg-7GYoK8eV0LDuC7Nv div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-7GYoK8eV0LDuC7Nv .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-7GYoK8eV0LDuC7Nv rect.text{fill:none;stroke-width:0;}#mermaid-svg-7GYoK8eV0LDuC7Nv .icon-shape,#mermaid-svg-7GYoK8eV0LDuC7Nv .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-7GYoK8eV0LDuC7Nv .icon-shape p,#mermaid-svg-7GYoK8eV0LDuC7Nv .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-7GYoK8eV0LDuC7Nv .icon-shape .label rect,#mermaid-svg-7GYoK8eV0LDuC7Nv .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-7GYoK8eV0LDuC7Nv .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-7GYoK8eV0LDuC7Nv .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-7GYoK8eV0LDuC7Nv :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 步骤1 环境与数据
步骤2 EDA 不平衡认知
步骤3 分层划分
步骤4~8 模型与阈值
步骤9 项目总结
1.4 名词解释(本步首次出现)
| 名词 | 是什么 | 为什么需要 | 在本项目中 | 易混淆 |
|---|---|---|---|---|
| 分类问题 | 预测离散类别(如 0/1) | 欺诈检测是「正常 vs 欺诈」 | 标签列 Class |
不是回归(连续值) |
| 不平衡分类 | 各类别样本数量悬殊 | 欺诈极少,Accuracy 会误导 | 492 欺诈 vs 284315 正常 | 不是均衡二分类 |
| creditcard.csv | Kaggle 经典欺诈数据集 | 本项目的训练数据 | 284807 行 31 列 | 不是原始刷卡明细 |
| V1~V28 | PCA 降维后的匿名特征 | 保护隐私,无法还原原始商户信息 | 除 Time、Amount 外的 28 列 | 不是手工业务特征 |
| imbalanced-learn | 处理不平衡数据的 Python 库 | 提供 SMOTE 等过采样方法 | 步骤 6 使用 | 不是 sklearn 内置 |
1.5 项目目录结构
project_02_fraud/
├── 教学文档.md # 详细教学(本文件)
├── README.md # 你的学习笔记
├── data/
│ └── creditcard.csv # 数据集(约 144 MB,本地缓存)
├── src/
│ └── train.py # 主训练脚本
├── reports/figures/ # 图表输出
└── models/ # 最终模型保存
#mermaid-svg-DqIFlLivY2a7KS29{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-DqIFlLivY2a7KS29 .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-DqIFlLivY2a7KS29 .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-DqIFlLivY2a7KS29 .error-icon{fill:#552222;}#mermaid-svg-DqIFlLivY2a7KS29 .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-DqIFlLivY2a7KS29 .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-DqIFlLivY2a7KS29 .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-DqIFlLivY2a7KS29 .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-DqIFlLivY2a7KS29 .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-DqIFlLivY2a7KS29 .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-DqIFlLivY2a7KS29 .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-DqIFlLivY2a7KS29 .marker{fill:#333333;stroke:#333333;}#mermaid-svg-DqIFlLivY2a7KS29 .marker.cross{stroke:#333333;}#mermaid-svg-DqIFlLivY2a7KS29 svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-DqIFlLivY2a7KS29 p{margin:0;}#mermaid-svg-DqIFlLivY2a7KS29 .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-DqIFlLivY2a7KS29 .cluster-label text{fill:#333;}#mermaid-svg-DqIFlLivY2a7KS29 .cluster-label span{color:#333;}#mermaid-svg-DqIFlLivY2a7KS29 .cluster-label span p{background-color:transparent;}#mermaid-svg-DqIFlLivY2a7KS29 .label text,#mermaid-svg-DqIFlLivY2a7KS29 span{fill:#333;color:#333;}#mermaid-svg-DqIFlLivY2a7KS29 .node rect,#mermaid-svg-DqIFlLivY2a7KS29 .node circle,#mermaid-svg-DqIFlLivY2a7KS29 .node ellipse,#mermaid-svg-DqIFlLivY2a7KS29 .node polygon,#mermaid-svg-DqIFlLivY2a7KS29 .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-DqIFlLivY2a7KS29 .rough-node .label text,#mermaid-svg-DqIFlLivY2a7KS29 .node .label text,#mermaid-svg-DqIFlLivY2a7KS29 .image-shape .label,#mermaid-svg-DqIFlLivY2a7KS29 .icon-shape .label{text-anchor:middle;}#mermaid-svg-DqIFlLivY2a7KS29 .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-DqIFlLivY2a7KS29 .rough-node .label,#mermaid-svg-DqIFlLivY2a7KS29 .node .label,#mermaid-svg-DqIFlLivY2a7KS29 .image-shape .label,#mermaid-svg-DqIFlLivY2a7KS29 .icon-shape .label{text-align:center;}#mermaid-svg-DqIFlLivY2a7KS29 .node.clickable{cursor:pointer;}#mermaid-svg-DqIFlLivY2a7KS29 .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-DqIFlLivY2a7KS29 .arrowheadPath{fill:#333333;}#mermaid-svg-DqIFlLivY2a7KS29 .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-DqIFlLivY2a7KS29 .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-DqIFlLivY2a7KS29 .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-DqIFlLivY2a7KS29 .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-DqIFlLivY2a7KS29 .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-DqIFlLivY2a7KS29 .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-DqIFlLivY2a7KS29 .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-DqIFlLivY2a7KS29 .cluster text{fill:#333;}#mermaid-svg-DqIFlLivY2a7KS29 .cluster span{color:#333;}#mermaid-svg-DqIFlLivY2a7KS29 div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-DqIFlLivY2a7KS29 .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-DqIFlLivY2a7KS29 rect.text{fill:none;stroke-width:0;}#mermaid-svg-DqIFlLivY2a7KS29 .icon-shape,#mermaid-svg-DqIFlLivY2a7KS29 .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-DqIFlLivY2a7KS29 .icon-shape p,#mermaid-svg-DqIFlLivY2a7KS29 .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-DqIFlLivY2a7KS29 .icon-shape .label rect,#mermaid-svg-DqIFlLivY2a7KS29 .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-DqIFlLivY2a7KS29 .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-DqIFlLivY2a7KS29 .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-DqIFlLivY2a7KS29 :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} project_02_fraud/
教学文档.md
data/creditcard.csv
src/train.py
reports/
1.6 任务清单
- 创建
project_02_fraud/目录结构 - 下载
creditcard.csv到data/ - 安装
imbalanced-learn - 编写
src/train.py(含load_data()、main()) - 运行脚本,打印前 5 行
1.7 运行本步
powershell
cd "d:\JavaCode\机器学习"
pip install -r requirements.txt
cd project_02_fraud
python src/train.py
1.8 数据集概览(你的环境)
| 项目 | 数值 |
|---|---|
| 总行数 | 284,807 |
| 总列数 | 31(Time + V1~V28 + Amount + Class) |
| 正常交易 (Class=0) | 284,315(99.827%) |
| 欺诈交易 (Class=1) | 492(0.173%) |
关键印象:欺诈样本不到 500 条,却混在 28 万条正常交易里------这就是「极度不平衡」。
1.9 核心代码解读
(1)load_data() ------ 本地优先 + 自动下载
python
if DATA_PATH.exists():
return pd.read_csv(DATA_PATH)
_download_data(DATA_DOWNLOAD_URL, DATA_PATH)
return pd.read_csv(DATA_PATH)
| 要点 | 说明 |
|---|---|
| 本地优先 | 已下载则秒开,不重复下载 |
| HuggingFace 备用 | 换电脑时运行脚本可自动拉取 |
| 不提交 Git | 144 MB 太大,见 .gitignore |
(2)与项目一的对比
| 对比项 | 项目一(房价) | 项目二(欺诈) |
|---|---|---|
| 问题类型 | 回归 | 二分类 |
| 标签 | MedHouseVal(连续) | Class(0/1) |
| 数据规模 | ~2 万 | ~28 万 |
| 核心难点 | 非线性 | 类别不平衡 |
1.10 动手任务
任务 A :运行 python src/train.py,确认输出 284807 行
任务 B :在 Python 中执行 df['Class'].value_counts(),手算欺诈占比
任务 C:思考:若模型「全部预测为正常」,Accuracy 是多少?
任务 D:在 README 步骤 1 写下你的日期和一句话感受
1.11 验收标准
- 能
pd.read_csv加载并打印前 5 行 - 能说出数据集行数、列数、欺诈占比
- 知道
imbalanced-learn的用途(步骤 6 再用) - 理解本项目是分类而非回归
1.12 常见问题
1.12 动手任务与验收标准参考答案
以下为教学标准答案,便于自学对照;
README.md学习记录仍建议用自己的话写。
动手任务答案
| 任务 | 参考答案 |
|---|---|
| A | 284807 行,无报错。 |
| B | 492/284807≈0.1727% 欺诈。 |
| C | 全猜正常 Accuracy≈99.83%,欺诈 Recall=0。 |
| D | 示例:Accuracy 会骗人。 |
验收标准答案
| 验收项 | 参考答案 |
|---|---|
| read_csv | 能加载并 head()。 |
| 行数列数占比 | 284807 行,31 列,欺诈 0.17%。 |
| imbalanced-learn | 处理不平衡,步骤 6 SMOTE 用。 |
| 分类非回归 | 预测 0/1 类别,不是连续值。 |
Q:数据从哪下载?
A:本步已从 HuggingFace 下载到 data/creditcard.csv。也可从 Kaggle 手动下载同名文件。
Q:为何 V1~V28 看不懂?
A:原始特征经 PCA 匿名化,只有 Amount、Time 有业务含义,V 列是数学变换结果。
Q:144 MB 为何不进 Git?
A:体积过大,已加入 .gitignore。克隆仓库后运行 train.py 可自动下载。
1.13 本步小结
| 要点 | 内容 |
|---|---|
| 问题类型 | 二分类(正常 vs 欺诈) |
| 数据规模 | 284,807 条 |
| 欺诈占比 | 约 0.17% |
| 新增依赖 | imbalanced-learn |
| 下一步 | EDA 与不平衡认知 |
1.14 学习记录(请你填写)
- 完成日期:
- 动手任务完成情况:任务 A / B / C / D
- 我对不平衡分类的初印象:
- 疑问(如有):
步骤 2:EDA 与不平衡认知
状态 :✅ 已完成教学(报告见
reports/eda_imbalance_report.txt,图表见01_~04_系列 PNG)
2.1 本步目标
- 量化 Class 分布,直观感受欺诈占比极低
- 计算 Always-Negative 基线(全预测正常)的 Accuracy
- 绘制 Amount 原始分布与 log1p 变换后分布
- 理解为何 Accuracy 在此场景是误导性指标
2.2 这一步在解决什么问题?
步骤 1 已知欺诈约占 0.17%,但「0.17%」还不够直观。本步要回答:
- 若我做一个什么都不干、全猜正常的模型,指标会怎样?
- 为什么领导看到「99.8% 准确率」可能仍要骂你?
- 交易金额 Amount 长什么样,正常与欺诈有无差异?
这是后续所有模型对比的认知地基。
2.3 本步在整体流程中的位置
#mermaid-svg-V3Z4WdoWbngD6MaD{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-V3Z4WdoWbngD6MaD .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-V3Z4WdoWbngD6MaD .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-V3Z4WdoWbngD6MaD .error-icon{fill:#552222;}#mermaid-svg-V3Z4WdoWbngD6MaD .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-V3Z4WdoWbngD6MaD .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-V3Z4WdoWbngD6MaD .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-V3Z4WdoWbngD6MaD .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-V3Z4WdoWbngD6MaD .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-V3Z4WdoWbngD6MaD .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-V3Z4WdoWbngD6MaD .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-V3Z4WdoWbngD6MaD .marker{fill:#333333;stroke:#333333;}#mermaid-svg-V3Z4WdoWbngD6MaD .marker.cross{stroke:#333333;}#mermaid-svg-V3Z4WdoWbngD6MaD svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-V3Z4WdoWbngD6MaD p{margin:0;}#mermaid-svg-V3Z4WdoWbngD6MaD .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-V3Z4WdoWbngD6MaD .cluster-label text{fill:#333;}#mermaid-svg-V3Z4WdoWbngD6MaD .cluster-label span{color:#333;}#mermaid-svg-V3Z4WdoWbngD6MaD .cluster-label span p{background-color:transparent;}#mermaid-svg-V3Z4WdoWbngD6MaD .label text,#mermaid-svg-V3Z4WdoWbngD6MaD span{fill:#333;color:#333;}#mermaid-svg-V3Z4WdoWbngD6MaD .node rect,#mermaid-svg-V3Z4WdoWbngD6MaD .node circle,#mermaid-svg-V3Z4WdoWbngD6MaD .node ellipse,#mermaid-svg-V3Z4WdoWbngD6MaD .node polygon,#mermaid-svg-V3Z4WdoWbngD6MaD .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-V3Z4WdoWbngD6MaD .rough-node .label text,#mermaid-svg-V3Z4WdoWbngD6MaD .node .label text,#mermaid-svg-V3Z4WdoWbngD6MaD .image-shape .label,#mermaid-svg-V3Z4WdoWbngD6MaD .icon-shape .label{text-anchor:middle;}#mermaid-svg-V3Z4WdoWbngD6MaD .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-V3Z4WdoWbngD6MaD .rough-node .label,#mermaid-svg-V3Z4WdoWbngD6MaD .node .label,#mermaid-svg-V3Z4WdoWbngD6MaD .image-shape .label,#mermaid-svg-V3Z4WdoWbngD6MaD .icon-shape .label{text-align:center;}#mermaid-svg-V3Z4WdoWbngD6MaD .node.clickable{cursor:pointer;}#mermaid-svg-V3Z4WdoWbngD6MaD .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-V3Z4WdoWbngD6MaD .arrowheadPath{fill:#333333;}#mermaid-svg-V3Z4WdoWbngD6MaD .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-V3Z4WdoWbngD6MaD .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-V3Z4WdoWbngD6MaD .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-V3Z4WdoWbngD6MaD .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-V3Z4WdoWbngD6MaD .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-V3Z4WdoWbngD6MaD .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-V3Z4WdoWbngD6MaD .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-V3Z4WdoWbngD6MaD .cluster text{fill:#333;}#mermaid-svg-V3Z4WdoWbngD6MaD .cluster span{color:#333;}#mermaid-svg-V3Z4WdoWbngD6MaD div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-V3Z4WdoWbngD6MaD .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-V3Z4WdoWbngD6MaD rect.text{fill:none;stroke-width:0;}#mermaid-svg-V3Z4WdoWbngD6MaD .icon-shape,#mermaid-svg-V3Z4WdoWbngD6MaD .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-V3Z4WdoWbngD6MaD .icon-shape p,#mermaid-svg-V3Z4WdoWbngD6MaD .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-V3Z4WdoWbngD6MaD .icon-shape .label rect,#mermaid-svg-V3Z4WdoWbngD6MaD .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-V3Z4WdoWbngD6MaD .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-V3Z4WdoWbngD6MaD .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-V3Z4WdoWbngD6MaD :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 步骤1 加载数据
步骤2 EDA 不平衡认知
Always-Negative 基线 99.83%
Amount 分布图
步骤3 分层划分
2.4 名词解释(本步首次出现)
| 名词 | 是什么 | 为什么需要 | 在本项目中 | 易混淆 |
|---|---|---|---|---|
| Accuracy | 预测正确的样本占总样本比例 | 最直观的指标,但不平衡时失效 | 全猜正常可达 99.83% | 不是唯一指标 |
| Always-Negative | 永远预测负类(正常)的 Dummy 策略 | 建立最低基线,检验指标是否误导 | Accuracy 高但 Recall=0 | 不是真实模型 |
| Recall(召回率) | 真实欺诈中被抓出的比例 TP/(TP+FN) | 风控更怕漏报欺诈 | 基线为 0 | 不是 Precision |
| log1p 变换 | 计算 log(1+x) | Amount 右偏严重,取对数便于看图 | 03_amount_log_distribution.png |
不是标准化 |
| 右偏分布 | 大量小值、少数极大值 | 直方图会挤在左侧 | Amount max 约 25691 | 不是正态分布 |
2.5 Always-Negative 基线(Mermaid)
#mermaid-svg-SwMsYxIXSHpn2Hus{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-SwMsYxIXSHpn2Hus .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-SwMsYxIXSHpn2Hus .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-SwMsYxIXSHpn2Hus .error-icon{fill:#552222;}#mermaid-svg-SwMsYxIXSHpn2Hus .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-SwMsYxIXSHpn2Hus .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-SwMsYxIXSHpn2Hus .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-SwMsYxIXSHpn2Hus .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-SwMsYxIXSHpn2Hus .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-SwMsYxIXSHpn2Hus .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-SwMsYxIXSHpn2Hus .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-SwMsYxIXSHpn2Hus .marker{fill:#333333;stroke:#333333;}#mermaid-svg-SwMsYxIXSHpn2Hus .marker.cross{stroke:#333333;}#mermaid-svg-SwMsYxIXSHpn2Hus svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-SwMsYxIXSHpn2Hus p{margin:0;}#mermaid-svg-SwMsYxIXSHpn2Hus .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-SwMsYxIXSHpn2Hus .cluster-label text{fill:#333;}#mermaid-svg-SwMsYxIXSHpn2Hus .cluster-label span{color:#333;}#mermaid-svg-SwMsYxIXSHpn2Hus .cluster-label span p{background-color:transparent;}#mermaid-svg-SwMsYxIXSHpn2Hus .label text,#mermaid-svg-SwMsYxIXSHpn2Hus span{fill:#333;color:#333;}#mermaid-svg-SwMsYxIXSHpn2Hus .node rect,#mermaid-svg-SwMsYxIXSHpn2Hus .node circle,#mermaid-svg-SwMsYxIXSHpn2Hus .node ellipse,#mermaid-svg-SwMsYxIXSHpn2Hus .node polygon,#mermaid-svg-SwMsYxIXSHpn2Hus .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-SwMsYxIXSHpn2Hus .rough-node .label text,#mermaid-svg-SwMsYxIXSHpn2Hus .node .label text,#mermaid-svg-SwMsYxIXSHpn2Hus .image-shape .label,#mermaid-svg-SwMsYxIXSHpn2Hus .icon-shape .label{text-anchor:middle;}#mermaid-svg-SwMsYxIXSHpn2Hus .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-SwMsYxIXSHpn2Hus .rough-node .label,#mermaid-svg-SwMsYxIXSHpn2Hus .node .label,#mermaid-svg-SwMsYxIXSHpn2Hus .image-shape .label,#mermaid-svg-SwMsYxIXSHpn2Hus .icon-shape .label{text-align:center;}#mermaid-svg-SwMsYxIXSHpn2Hus .node.clickable{cursor:pointer;}#mermaid-svg-SwMsYxIXSHpn2Hus .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-SwMsYxIXSHpn2Hus .arrowheadPath{fill:#333333;}#mermaid-svg-SwMsYxIXSHpn2Hus .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-SwMsYxIXSHpn2Hus .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-SwMsYxIXSHpn2Hus .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-SwMsYxIXSHpn2Hus .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-SwMsYxIXSHpn2Hus .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-SwMsYxIXSHpn2Hus .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-SwMsYxIXSHpn2Hus .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-SwMsYxIXSHpn2Hus .cluster text{fill:#333;}#mermaid-svg-SwMsYxIXSHpn2Hus .cluster span{color:#333;}#mermaid-svg-SwMsYxIXSHpn2Hus div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-SwMsYxIXSHpn2Hus .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-SwMsYxIXSHpn2Hus rect.text{fill:none;stroke-width:0;}#mermaid-svg-SwMsYxIXSHpn2Hus .icon-shape,#mermaid-svg-SwMsYxIXSHpn2Hus .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-SwMsYxIXSHpn2Hus .icon-shape p,#mermaid-svg-SwMsYxIXSHpn2Hus .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-SwMsYxIXSHpn2Hus .icon-shape .label rect,#mermaid-svg-SwMsYxIXSHpn2Hus .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-SwMsYxIXSHpn2Hus .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-SwMsYxIXSHpn2Hus .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-SwMsYxIXSHpn2Hus :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 指标
结果
Dummy 模型 全预测正常
每条交易输出 Class=0
TN=284315 正常猜对
FN=492 欺诈全漏
Accuracy 99.83%
欺诈 Recall 0%
业务解读 :银行若采用这种策略,492 笔欺诈一笔都抓不到,但报表上 Accuracy 仍接近 100%。
2.6 任务清单
- 打印
Class的value_counts()及占比 - 计算全预测正常的 Accuracy(≈ 99.83%)
- 绘制 Amount 原始分布与 log1p 分布
- 按类别对比 Amount(箱线图)
- 保存 EDA 报告与图表
2.7 运行本步
powershell
cd "d:\JavaCode\机器学习\project_02_fraud"
python src/train.py
2.8 实验结果(你的环境)
Class 分布:
| 类别 | 数量 | 占比 |
|---|---|---|
| 0 正常 | 284,315 | 99.8273% |
| 1 欺诈 | 492 | 0.1727% |
Always-Negative 基线:
| 指标 | 数值 | 含义 |
|---|---|---|
| Accuracy | 0.9983(99.83%) | 几乎全对------因为几乎全是正常 |
| 欺诈 Recall | 0.0000 | 一个欺诈都没抓到 |
| TP / FP / TN / FN | 0 / 0 / 284315 / 492 | 492 条欺诈全部 FN |
Amount 按类别(describe):
| Class | mean | 50% | max |
|---|---|---|---|
| 0 正常 | 88.29 | 22.00 | 25691.16 |
| 1 欺诈 | 122.21 | 9.25 | 2125.87 |
欺诈平均金额略高,但分布重叠大,单靠 Amount 无法完美区分。
2.9 为何 Accuracy 会误导?(Mermaid)
#mermaid-svg-0Bg3SrfoFRKmuQuC{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-0Bg3SrfoFRKmuQuC .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-0Bg3SrfoFRKmuQuC .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-0Bg3SrfoFRKmuQuC .error-icon{fill:#552222;}#mermaid-svg-0Bg3SrfoFRKmuQuC .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-0Bg3SrfoFRKmuQuC .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-0Bg3SrfoFRKmuQuC .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-0Bg3SrfoFRKmuQuC .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-0Bg3SrfoFRKmuQuC .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-0Bg3SrfoFRKmuQuC .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-0Bg3SrfoFRKmuQuC .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-0Bg3SrfoFRKmuQuC .marker{fill:#333333;stroke:#333333;}#mermaid-svg-0Bg3SrfoFRKmuQuC .marker.cross{stroke:#333333;}#mermaid-svg-0Bg3SrfoFRKmuQuC svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-0Bg3SrfoFRKmuQuC p{margin:0;}#mermaid-svg-0Bg3SrfoFRKmuQuC .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-0Bg3SrfoFRKmuQuC .cluster-label text{fill:#333;}#mermaid-svg-0Bg3SrfoFRKmuQuC .cluster-label span{color:#333;}#mermaid-svg-0Bg3SrfoFRKmuQuC .cluster-label span p{background-color:transparent;}#mermaid-svg-0Bg3SrfoFRKmuQuC .label text,#mermaid-svg-0Bg3SrfoFRKmuQuC span{fill:#333;color:#333;}#mermaid-svg-0Bg3SrfoFRKmuQuC .node rect,#mermaid-svg-0Bg3SrfoFRKmuQuC .node circle,#mermaid-svg-0Bg3SrfoFRKmuQuC .node ellipse,#mermaid-svg-0Bg3SrfoFRKmuQuC .node polygon,#mermaid-svg-0Bg3SrfoFRKmuQuC .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-0Bg3SrfoFRKmuQuC .rough-node .label text,#mermaid-svg-0Bg3SrfoFRKmuQuC .node .label text,#mermaid-svg-0Bg3SrfoFRKmuQuC .image-shape .label,#mermaid-svg-0Bg3SrfoFRKmuQuC .icon-shape .label{text-anchor:middle;}#mermaid-svg-0Bg3SrfoFRKmuQuC .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-0Bg3SrfoFRKmuQuC .rough-node .label,#mermaid-svg-0Bg3SrfoFRKmuQuC .node .label,#mermaid-svg-0Bg3SrfoFRKmuQuC .image-shape .label,#mermaid-svg-0Bg3SrfoFRKmuQuC .icon-shape .label{text-align:center;}#mermaid-svg-0Bg3SrfoFRKmuQuC .node.clickable{cursor:pointer;}#mermaid-svg-0Bg3SrfoFRKmuQuC .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-0Bg3SrfoFRKmuQuC .arrowheadPath{fill:#333333;}#mermaid-svg-0Bg3SrfoFRKmuQuC .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-0Bg3SrfoFRKmuQuC .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-0Bg3SrfoFRKmuQuC .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-0Bg3SrfoFRKmuQuC .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-0Bg3SrfoFRKmuQuC .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-0Bg3SrfoFRKmuQuC .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-0Bg3SrfoFRKmuQuC .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-0Bg3SrfoFRKmuQuC .cluster text{fill:#333;}#mermaid-svg-0Bg3SrfoFRKmuQuC .cluster span{color:#333;}#mermaid-svg-0Bg3SrfoFRKmuQuC div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-0Bg3SrfoFRKmuQuC .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-0Bg3SrfoFRKmuQuC rect.text{fill:none;stroke-width:0;}#mermaid-svg-0Bg3SrfoFRKmuQuC .icon-shape,#mermaid-svg-0Bg3SrfoFRKmuQuC .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-0Bg3SrfoFRKmuQuC .icon-shape p,#mermaid-svg-0Bg3SrfoFRKmuQuC .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-0Bg3SrfoFRKmuQuC .icon-shape .label rect,#mermaid-svg-0Bg3SrfoFRKmuQuC .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-0Bg3SrfoFRKmuQuC .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-0Bg3SrfoFRKmuQuC .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-0Bg3SrfoFRKmuQuC :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 284807 条交易
284315 条正常 占 99.83%
492 条欺诈 占 0.17%
全猜正常 284315 条猜对
492 条全漏 FN
Accuracy 显示 99.83% 看起来很好
Recall 为 0 业务完全失败
2.10 核心代码解读
(1)Always-Negative 基线计算
python
accuracy = n_normal / total # 284315 / 284807 ≈ 0.9983
recall_fraud = tp / (tp + fn) # 0 / 492 = 0
全预测 0 时,只有正常类被「猜对」,欺诈类全部成为 FN(假阴性)。
(2)log1p 变换
python
amount_log = np.log1p(df["Amount"]) # log(1 + Amount)
Amount 从 0 到 25691,原始直方图挤在左侧;log1p 压缩大值、展开小值,形状更易观察。
2.11 输出文件
| 文件 | 说明 |
|---|---|
reports/eda_imbalance_report.txt |
EDA 与基线文字报告 |
reports/figures/01_交易类别分布.png |
类别计数条形图 |
reports/figures/02_交易金额原始分布.png |
Amount 原始分布 |
reports/figures/03_交易金额对数分布.png |
log1p(Amount) 分布 |
reports/figures/04_各类别金额箱线图.png |
正常 vs 欺诈 Amount 箱线图 |
2.12 动手任务
任务 A :运行脚本,确认 Always-Negative Accuracy ≈ 99.83%
任务 B :打开 01_class_distribution.png,对比两根柱子高度差
任务 C:用自己的话解释:为什么「99.83% 准确率」的模型可能完全没用?
任务 D :比较 02 与 03 两张 Amount 图,说明为何要 log 变换
2.13 验收标准
- 能说出欺诈占比约 0.17%
- 能计算/解释 Always-Negative 的 Accuracy 与 Recall
- 能口头解释「高 Accuracy 模型可能完全没用」
- 知道后续应关注 Precision、Recall、F1 而非只看 Accuracy
2.14 常见问题
2.14 动手任务与验收标准参考答案
以下为教学标准答案,便于自学对照;
README.md学习记录仍建议用自己的话写。
动手任务答案
| 任务 | 参考答案 |
|---|---|
| A | Always-Negative Accuracy≈99.83%,Recall=0。 |
| B | 正常柱极高,欺诈柱几乎看不见。 |
| C | 高 Accuracy 但一条欺诈未抓,完全无用。 |
| D | 原始 Amount 右偏;log 后更对称。 |
验收标准答案
| 验收项 | 参考答案 |
|---|---|
| 欺诈占比 | 约 0.17%。 |
| Always-Negative | 永远预测 0 的基线。 |
| 高 Acc 无用 | 必须看 Recall/FN。 |
| Accuracy 误导 | 不平衡场景不能只看 Accuracy。 |
Q:99.83% 的模型能上线吗?
A:若它是全猜正常,绝对不能。Accuracy 高只是因为负类太多。
Q:欺诈 Recall 为什么是 0?
A:模型从未预测欺诈(全为 0),TP=0,Recall = 0/(0+492) = 0。
Q:Amount 对区分欺诈有用吗?
A:有一定差异但重叠大,需结合 V1~V28 等特征与后续模型。
Q:下一步做什么?
A:步骤 3 用 stratify 分层划分 train/test,保持欺诈比例一致。
2.15 本步小结
| 要点 | 内容 |
|---|---|
| 欺诈占比 | 0.1727% |
| Dummy Accuracy | 99.83% |
| Dummy 欺诈 Recall | 0 |
| 核心教训 | Accuracy 在不平衡场景会误导 |
| 下一步 | 分层划分训练/测试集 |
2.16 学习记录(请你填写)
- 完成日期:
- 动手任务完成情况:任务 A / B / C / D
- 我对 Accuracy 陷阱的理解:
- 疑问(如有):
步骤 3:划分数据 ------ 注意分层抽样
状态 :✅ 已完成教学(报告见
reports/train_test_split_report.txt,图表见05_、06_PNG)
3.1 本步目标
- 使用
train_test_split(..., stratify=y)做 80/20 划分 - 理解
stratify如何保持训练/测试中欺诈比例与全集一致 - 明确 数据泄露 边界:先划分,再(仅对训练集)过采样
3.2 这一步在解决什么问题?
欺诈只占 0.17%。若随机划分而不分层,测试集可能:
- 欺诈样本过少(甚至为 0),评估不稳定
- 训练集与测试集欺诈比例差异大,指标不可比
本步建立后续所有实验共用的 train/test 切分 ,并强调:SMOTE 必须等划分后再做。
3.3 本步在整体流程中的位置
#mermaid-svg-kgKFc1lFjAstFonm{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-kgKFc1lFjAstFonm .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-kgKFc1lFjAstFonm .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-kgKFc1lFjAstFonm .error-icon{fill:#552222;}#mermaid-svg-kgKFc1lFjAstFonm .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-kgKFc1lFjAstFonm .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-kgKFc1lFjAstFonm .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-kgKFc1lFjAstFonm .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-kgKFc1lFjAstFonm .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-kgKFc1lFjAstFonm .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-kgKFc1lFjAstFonm .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-kgKFc1lFjAstFonm .marker{fill:#333333;stroke:#333333;}#mermaid-svg-kgKFc1lFjAstFonm .marker.cross{stroke:#333333;}#mermaid-svg-kgKFc1lFjAstFonm svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-kgKFc1lFjAstFonm p{margin:0;}#mermaid-svg-kgKFc1lFjAstFonm .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-kgKFc1lFjAstFonm .cluster-label text{fill:#333;}#mermaid-svg-kgKFc1lFjAstFonm .cluster-label span{color:#333;}#mermaid-svg-kgKFc1lFjAstFonm .cluster-label span p{background-color:transparent;}#mermaid-svg-kgKFc1lFjAstFonm .label text,#mermaid-svg-kgKFc1lFjAstFonm span{fill:#333;color:#333;}#mermaid-svg-kgKFc1lFjAstFonm .node rect,#mermaid-svg-kgKFc1lFjAstFonm .node circle,#mermaid-svg-kgKFc1lFjAstFonm .node ellipse,#mermaid-svg-kgKFc1lFjAstFonm .node polygon,#mermaid-svg-kgKFc1lFjAstFonm .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-kgKFc1lFjAstFonm .rough-node .label text,#mermaid-svg-kgKFc1lFjAstFonm .node .label text,#mermaid-svg-kgKFc1lFjAstFonm .image-shape .label,#mermaid-svg-kgKFc1lFjAstFonm .icon-shape .label{text-anchor:middle;}#mermaid-svg-kgKFc1lFjAstFonm .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-kgKFc1lFjAstFonm .rough-node .label,#mermaid-svg-kgKFc1lFjAstFonm .node .label,#mermaid-svg-kgKFc1lFjAstFonm .image-shape .label,#mermaid-svg-kgKFc1lFjAstFonm .icon-shape .label{text-align:center;}#mermaid-svg-kgKFc1lFjAstFonm .node.clickable{cursor:pointer;}#mermaid-svg-kgKFc1lFjAstFonm .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-kgKFc1lFjAstFonm .arrowheadPath{fill:#333333;}#mermaid-svg-kgKFc1lFjAstFonm .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-kgKFc1lFjAstFonm .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-kgKFc1lFjAstFonm .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-kgKFc1lFjAstFonm .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-kgKFc1lFjAstFonm .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-kgKFc1lFjAstFonm .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-kgKFc1lFjAstFonm .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-kgKFc1lFjAstFonm .cluster text{fill:#333;}#mermaid-svg-kgKFc1lFjAstFonm .cluster span{color:#333;}#mermaid-svg-kgKFc1lFjAstFonm div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-kgKFc1lFjAstFonm .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-kgKFc1lFjAstFonm rect.text{fill:none;stroke-width:0;}#mermaid-svg-kgKFc1lFjAstFonm .icon-shape,#mermaid-svg-kgKFc1lFjAstFonm .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-kgKFc1lFjAstFonm .icon-shape p,#mermaid-svg-kgKFc1lFjAstFonm .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-kgKFc1lFjAstFonm .icon-shape .label rect,#mermaid-svg-kgKFc1lFjAstFonm .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-kgKFc1lFjAstFonm .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-kgKFc1lFjAstFonm .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-kgKFc1lFjAstFonm :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 步骤2 认知不平衡
步骤3 分层划分
X_train 227845 条
X_test 56962 条
步骤4~8 仅 fit 训练集
步骤4~8 仅 predict 评估
步骤6 SMOTE 仅训练集
3.4 名词解释(本步首次出现)
| 名词 | 是什么 | 为什么需要 | 在本项目中 | 易混淆 |
|---|---|---|---|---|
| stratify | 划分时按标签比例分层抽样 | 保证 train/test 欺诈占比接近全集 | stratify=y |
不是 shuffle |
| 分层抽样 | 各子集保持与总体相同的类别比例 | 欺诈极少,随机划分易偏 | 全集 0.1727% ≈ 训练 0.1729% | 不是过采样 |
| 数据泄露 | 测试集信息间接进入训练 | 指标虚高、上线失效 | 全量 SMOTE 再划分是错误 | 不是过拟合 |
| fit 范围 | 模型只应学习训练集 | 测试集模拟「未来未见数据」 | 步骤 4 起只在 X_train 上 fit | 不是交叉验证 |
3.5 正确 vs 错误流程(Mermaid)
#mermaid-svg-w11INHMmq8yCYvUu{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-w11INHMmq8yCYvUu .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-w11INHMmq8yCYvUu .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-w11INHMmq8yCYvUu .error-icon{fill:#552222;}#mermaid-svg-w11INHMmq8yCYvUu .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-w11INHMmq8yCYvUu .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-w11INHMmq8yCYvUu .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-w11INHMmq8yCYvUu .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-w11INHMmq8yCYvUu .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-w11INHMmq8yCYvUu .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-w11INHMmq8yCYvUu .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-w11INHMmq8yCYvUu .marker{fill:#333333;stroke:#333333;}#mermaid-svg-w11INHMmq8yCYvUu .marker.cross{stroke:#333333;}#mermaid-svg-w11INHMmq8yCYvUu svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-w11INHMmq8yCYvUu p{margin:0;}#mermaid-svg-w11INHMmq8yCYvUu .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-w11INHMmq8yCYvUu .cluster-label text{fill:#333;}#mermaid-svg-w11INHMmq8yCYvUu .cluster-label span{color:#333;}#mermaid-svg-w11INHMmq8yCYvUu .cluster-label span p{background-color:transparent;}#mermaid-svg-w11INHMmq8yCYvUu .label text,#mermaid-svg-w11INHMmq8yCYvUu span{fill:#333;color:#333;}#mermaid-svg-w11INHMmq8yCYvUu .node rect,#mermaid-svg-w11INHMmq8yCYvUu .node circle,#mermaid-svg-w11INHMmq8yCYvUu .node ellipse,#mermaid-svg-w11INHMmq8yCYvUu .node polygon,#mermaid-svg-w11INHMmq8yCYvUu .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-w11INHMmq8yCYvUu .rough-node .label text,#mermaid-svg-w11INHMmq8yCYvUu .node .label text,#mermaid-svg-w11INHMmq8yCYvUu .image-shape .label,#mermaid-svg-w11INHMmq8yCYvUu .icon-shape .label{text-anchor:middle;}#mermaid-svg-w11INHMmq8yCYvUu .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-w11INHMmq8yCYvUu .rough-node .label,#mermaid-svg-w11INHMmq8yCYvUu .node .label,#mermaid-svg-w11INHMmq8yCYvUu .image-shape .label,#mermaid-svg-w11INHMmq8yCYvUu .icon-shape .label{text-align:center;}#mermaid-svg-w11INHMmq8yCYvUu .node.clickable{cursor:pointer;}#mermaid-svg-w11INHMmq8yCYvUu .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-w11INHMmq8yCYvUu .arrowheadPath{fill:#333333;}#mermaid-svg-w11INHMmq8yCYvUu .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-w11INHMmq8yCYvUu .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-w11INHMmq8yCYvUu .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-w11INHMmq8yCYvUu .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-w11INHMmq8yCYvUu .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-w11INHMmq8yCYvUu .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-w11INHMmq8yCYvUu .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-w11INHMmq8yCYvUu .cluster text{fill:#333;}#mermaid-svg-w11INHMmq8yCYvUu .cluster span{color:#333;}#mermaid-svg-w11INHMmq8yCYvUu div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-w11INHMmq8yCYvUu .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-w11INHMmq8yCYvUu rect.text{fill:none;stroke-width:0;}#mermaid-svg-w11INHMmq8yCYvUu .icon-shape,#mermaid-svg-w11INHMmq8yCYvUu .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-w11INHMmq8yCYvUu .icon-shape p,#mermaid-svg-w11INHMmq8yCYvUu .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-w11INHMmq8yCYvUu .icon-shape .label rect,#mermaid-svg-w11INHMmq8yCYvUu .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-w11INHMmq8yCYvUu .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-w11INHMmq8yCYvUu .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-w11INHMmq8yCYvUu :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 错误流程
加载全量数据
全量 SMOTE
再划分 train/test
指标虚高 泄露
正确流程
加载全量数据
stratify 划分
训练集 SMOTE 可选
fit 训练集
predict 测试集
3.6 任务清单
-
split_features_target()分离 X(30 列)与 y(Class) -
train_test_split(..., stratify=y, test_size=0.2, random_state=42) - 对比全集/训练/测试欺诈占比
- 说明暂不 SMOTE、强调数据泄露
- 保存划分报告与对比图
3.7 运行本步
powershell
cd "d:\JavaCode\机器学习\project_02_fraud"
python src/train.py
3.8 实验结果(你的环境)
| 数据集 | 样本数 | 欺诈数 | 欺诈占比 |
|---|---|---|---|
| 全集 | 284,807 | 492 | 0.1727% |
| 训练集 | 227,845 | 394 | 0.1729% |
| 测试集 | 56,962 | 98 | 0.1720% |
特征矩阵形状:
| 集合 | X 形状 | y 长度 |
|---|---|---|
| 训练集 | (227845, 30) | 227845 |
| 测试集 | (56962, 30) | 56962 |
三者欺诈占比几乎相同,说明 stratify 生效。
3.9 核心代码解读
(1)分层划分
python
X_train, X_test, y_train, y_test = train_test_split(
X, y,
test_size=0.2,
random_state=42,
stratify=y, # 关键:按 Class 比例分层
)
| 参数 | 含义 |
|---|---|
test_size=0.2 |
20% 测试,80% 训练 |
random_state=42 |
可复现 |
stratify=y |
训练/测试欺诈比例 ≈ 全集 |
(2)与项目一划分的区别
| 对比项 | 项目一(回归) | 项目二(不平衡分类) |
|---|---|---|
| stratify | 未使用 | 必须使用 |
| 关注点 | 标签均值接近 | 欺诈比例接近 |
| 测试集用途 | 算 RMSE | 算 Precision/Recall 等 |
3.10 输出文件
| 文件 | 说明 |
|---|---|
reports/train_test_split_report.txt |
划分参数与欺诈比例 |
reports/figures/05_训练测试集数量对比.png |
训练/测试样本数对比 |
reports/figures/06_分层抽样欺诈占比对比.png |
欺诈占比三者对比 |
3.11 动手任务
任务 A :运行脚本,确认训练集 227,845 条、测试集 56,962 条
任务 B :核对三行欺诈占比是否都约 0.17%
任务 C:用自己的话解释:为何不能先 SMOTE 再划分?
任务 D:在 README 步骤 3 填写你的笔记
3.12 验收标准
- 能解释
stratify=y的作用 - 能说出训练/测试欺诈比例与全集接近
- 能说明「先过采样再划分」为何是数据泄露
- 知道测试集在训练阶段不可使用
3.13 常见问题
3.13 动手任务与验收标准参考答案
以下为教学标准答案,便于自学对照;
README.md学习记录仍建议用自己的话写。
动手任务答案
| 任务 | 参考答案 |
|---|---|
| A | 227845 / 56962。 |
| B | 三处欺诈占比均约 0.17%。 |
| C | 先 SMOTE 再划分会泄露/污染测试评估。 |
| D | stratify 保持类别比例。 |
验收标准答案
| 验收项 | 参考答案 |
|---|---|
| stratify | 分层保持欺诈比例。 |
| 比例接近 | 训练 0.1729%,测试 0.1720%。 |
| 先 SMOTE 错误 | 只能对训练集过采样。 |
| 测试集 | 训练阶段不可用。 |
Q:测试集只有 98 条欺诈,够吗?
A:对本数据集是标准做法。欺诈少是现实;后续用 PR-AUC 等更适合不平衡的指标。
Q:能否用 stratify 划分验证集?
A:可以。本教学项目简化为 train/test;生产环境常再划 val 做调参。
Q:random_state=42 换种子会怎样?
A:具体样本不同,但 stratify 下欺诈比例仍稳定。
3.14 本步小结
| 要点 | 内容 |
|---|---|
| 划分比例 | 80% 训练 / 20% 测试 |
| stratify | 欺诈占比 train≈test≈全集 |
| 训练集欺诈 | 394 条 |
| 测试集欺诈 | 98 条 |
| 下一步 | Logistic Regression 基准 |
3.15 学习记录(请你填写)
- 完成日期:
- 动手任务完成情况:任务 A / B / C / D
- 我对 stratify 与数据泄露的理解:
- 疑问(如有):
步骤 4:基准模型 Logistic Regression
状态 :✅ 已完成教学(报告见
reports/baseline_logistic_regression.txt,图表见07_逻辑回归基准混淆矩阵.png)
4.1 本步目标
- 用 StandardScaler 缩放 Amount(V1~V28 已是 PCA 结果,保持原样)
- 训练
LogisticRegression作为第一个真实分类模型(无 class_weight) - 输出 Accuracy、Precision、Recall、F1 与
classification_report - 绘制混淆矩阵热力图,理解 TP/FP/TN/FN
4.2 这一步在解决什么问题?
步骤 2 的 Dummy 模型「全猜正常」Recall=0。本步训练第一个真实模型,回答:
- 逻辑回归在不平衡数据上表现如何?
- Accuracy 很高是否代表模型好用?
- **漏报欺诈(FN)**有多少?误报正常(FP)有多少?
这是后续 class_weight、SMOTE、阈值调优的对比基准。
4.3 本步在整体流程中的位置
#mermaid-svg-bDHG2cepgtsKxjkc{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-bDHG2cepgtsKxjkc .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-bDHG2cepgtsKxjkc .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-bDHG2cepgtsKxjkc .error-icon{fill:#552222;}#mermaid-svg-bDHG2cepgtsKxjkc .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-bDHG2cepgtsKxjkc .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-bDHG2cepgtsKxjkc .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-bDHG2cepgtsKxjkc .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-bDHG2cepgtsKxjkc .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-bDHG2cepgtsKxjkc .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-bDHG2cepgtsKxjkc .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-bDHG2cepgtsKxjkc .marker{fill:#333333;stroke:#333333;}#mermaid-svg-bDHG2cepgtsKxjkc .marker.cross{stroke:#333333;}#mermaid-svg-bDHG2cepgtsKxjkc svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-bDHG2cepgtsKxjkc p{margin:0;}#mermaid-svg-bDHG2cepgtsKxjkc .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-bDHG2cepgtsKxjkc .cluster-label text{fill:#333;}#mermaid-svg-bDHG2cepgtsKxjkc .cluster-label span{color:#333;}#mermaid-svg-bDHG2cepgtsKxjkc .cluster-label span p{background-color:transparent;}#mermaid-svg-bDHG2cepgtsKxjkc .label text,#mermaid-svg-bDHG2cepgtsKxjkc span{fill:#333;color:#333;}#mermaid-svg-bDHG2cepgtsKxjkc .node rect,#mermaid-svg-bDHG2cepgtsKxjkc .node circle,#mermaid-svg-bDHG2cepgtsKxjkc .node ellipse,#mermaid-svg-bDHG2cepgtsKxjkc .node polygon,#mermaid-svg-bDHG2cepgtsKxjkc .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-bDHG2cepgtsKxjkc .rough-node .label text,#mermaid-svg-bDHG2cepgtsKxjkc .node .label text,#mermaid-svg-bDHG2cepgtsKxjkc .image-shape .label,#mermaid-svg-bDHG2cepgtsKxjkc .icon-shape .label{text-anchor:middle;}#mermaid-svg-bDHG2cepgtsKxjkc .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-bDHG2cepgtsKxjkc .rough-node .label,#mermaid-svg-bDHG2cepgtsKxjkc .node .label,#mermaid-svg-bDHG2cepgtsKxjkc .image-shape .label,#mermaid-svg-bDHG2cepgtsKxjkc .icon-shape .label{text-align:center;}#mermaid-svg-bDHG2cepgtsKxjkc .node.clickable{cursor:pointer;}#mermaid-svg-bDHG2cepgtsKxjkc .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-bDHG2cepgtsKxjkc .arrowheadPath{fill:#333333;}#mermaid-svg-bDHG2cepgtsKxjkc .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-bDHG2cepgtsKxjkc .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-bDHG2cepgtsKxjkc .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-bDHG2cepgtsKxjkc .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-bDHG2cepgtsKxjkc .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-bDHG2cepgtsKxjkc .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-bDHG2cepgtsKxjkc .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-bDHG2cepgtsKxjkc .cluster text{fill:#333;}#mermaid-svg-bDHG2cepgtsKxjkc .cluster span{color:#333;}#mermaid-svg-bDHG2cepgtsKxjkc div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-bDHG2cepgtsKxjkc .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-bDHG2cepgtsKxjkc rect.text{fill:none;stroke-width:0;}#mermaid-svg-bDHG2cepgtsKxjkc .icon-shape,#mermaid-svg-bDHG2cepgtsKxjkc .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-bDHG2cepgtsKxjkc .icon-shape p,#mermaid-svg-bDHG2cepgtsKxjkc .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-bDHG2cepgtsKxjkc .icon-shape .label rect,#mermaid-svg-bDHG2cepgtsKxjkc .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-bDHG2cepgtsKxjkc .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-bDHG2cepgtsKxjkc .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-bDHG2cepgtsKxjkc :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 步骤3 分层划分
步骤4 LR 基准
Amount 缩放
fit 训练集
predict 测试集
混淆矩阵与指标
步骤5 class_weight
4.4 名词解释(本步首次出现)
| 名词 | 是什么 | 为什么需要 | 在本项目中 | 易混淆 |
|---|---|---|---|---|
| 逻辑回归 LR | 线性分类模型,输出概率 | 简单可解释的基准 | 步骤 4 基准 | 不是回归 |
| Precision | 预测为欺诈中真是欺诈的比例 TP/(TP+FP) | 衡量误报率 | 测试约 0.82 | 不是 Recall |
| Recall | 真实欺诈中被抓出的比例 TP/(TP+FN) | 衡量漏报率 | 测试约 0.66 | 不是 Accuracy |
| F1 | Precision 与 Recall 的调和平均 | 综合衡量欺诈类 | 测试约 0.73 | 不是 Accuracy |
| 混淆矩阵 | 真实 vs 预测的四格表 | 看清 TP/FP/TN/FN | 07 号 PNG | 不是 ROC 曲线 |
| TP/FP/TN/FN | 真正例/假正例/真负例/假负例 | 风控:FN=漏报欺诈 | FN=33 需关注 | 不是准确率 |
4.5 混淆矩阵(Mermaid)
#mermaid-svg-gDAWqeNaB5d76auT{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-gDAWqeNaB5d76auT .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-gDAWqeNaB5d76auT .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-gDAWqeNaB5d76auT .error-icon{fill:#552222;}#mermaid-svg-gDAWqeNaB5d76auT .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-gDAWqeNaB5d76auT .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-gDAWqeNaB5d76auT .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-gDAWqeNaB5d76auT .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-gDAWqeNaB5d76auT .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-gDAWqeNaB5d76auT .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-gDAWqeNaB5d76auT .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-gDAWqeNaB5d76auT .marker{fill:#333333;stroke:#333333;}#mermaid-svg-gDAWqeNaB5d76auT .marker.cross{stroke:#333333;}#mermaid-svg-gDAWqeNaB5d76auT svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-gDAWqeNaB5d76auT p{margin:0;}#mermaid-svg-gDAWqeNaB5d76auT .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-gDAWqeNaB5d76auT .cluster-label text{fill:#333;}#mermaid-svg-gDAWqeNaB5d76auT .cluster-label span{color:#333;}#mermaid-svg-gDAWqeNaB5d76auT .cluster-label span p{background-color:transparent;}#mermaid-svg-gDAWqeNaB5d76auT .label text,#mermaid-svg-gDAWqeNaB5d76auT span{fill:#333;color:#333;}#mermaid-svg-gDAWqeNaB5d76auT .node rect,#mermaid-svg-gDAWqeNaB5d76auT .node circle,#mermaid-svg-gDAWqeNaB5d76auT .node ellipse,#mermaid-svg-gDAWqeNaB5d76auT .node polygon,#mermaid-svg-gDAWqeNaB5d76auT .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-gDAWqeNaB5d76auT .rough-node .label text,#mermaid-svg-gDAWqeNaB5d76auT .node .label text,#mermaid-svg-gDAWqeNaB5d76auT .image-shape .label,#mermaid-svg-gDAWqeNaB5d76auT .icon-shape .label{text-anchor:middle;}#mermaid-svg-gDAWqeNaB5d76auT .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-gDAWqeNaB5d76auT .rough-node .label,#mermaid-svg-gDAWqeNaB5d76auT .node .label,#mermaid-svg-gDAWqeNaB5d76auT .image-shape .label,#mermaid-svg-gDAWqeNaB5d76auT .icon-shape .label{text-align:center;}#mermaid-svg-gDAWqeNaB5d76auT .node.clickable{cursor:pointer;}#mermaid-svg-gDAWqeNaB5d76auT .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-gDAWqeNaB5d76auT .arrowheadPath{fill:#333333;}#mermaid-svg-gDAWqeNaB5d76auT .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-gDAWqeNaB5d76auT .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-gDAWqeNaB5d76auT .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-gDAWqeNaB5d76auT .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-gDAWqeNaB5d76auT .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-gDAWqeNaB5d76auT .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-gDAWqeNaB5d76auT .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-gDAWqeNaB5d76auT .cluster text{fill:#333;}#mermaid-svg-gDAWqeNaB5d76auT .cluster span{color:#333;}#mermaid-svg-gDAWqeNaB5d76auT div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-gDAWqeNaB5d76auT .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-gDAWqeNaB5d76auT rect.text{fill:none;stroke-width:0;}#mermaid-svg-gDAWqeNaB5d76auT .icon-shape,#mermaid-svg-gDAWqeNaB5d76auT .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-gDAWqeNaB5d76auT .icon-shape p,#mermaid-svg-gDAWqeNaB5d76auT .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-gDAWqeNaB5d76auT .icon-shape .label rect,#mermaid-svg-gDAWqeNaB5d76auT .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-gDAWqeNaB5d76auT .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-gDAWqeNaB5d76auT .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-gDAWqeNaB5d76auT :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 模型预测
预测正常 TN+FN
预测欺诈 FP+TP
真实标签
正常 56864
欺诈 98
四格含义(测试集本步结果):
| 预测正常 | 预测欺诈 | |
|---|---|---|
| 真实正常 | TN=56850 | FP=14 |
| 真实欺诈 | FN=33 | TP=65 |
- FN=33:漏报,风控最不愿看到
- FP=14:误报,打扰正常用户
4.6 任务清单
-
StandardScaler仅缩放 Amount 列 -
LogisticRegression(max_iter=2000, random_state=42)训练 - 输出 train/test 的 classification_report
- 绘制测试集混淆矩阵热力图
- 保存
baseline_logistic_regression.txt
4.7 运行本步
powershell
cd "d:\JavaCode\机器学习\project_02_fraud"
python src/train.py
4.8 实验结果(你的环境)
模型配置: LogisticRegression(max_iter=2000, random_state=42),无 class_weight
| 集合 | Accuracy | 欺诈 Precision | 欺诈 Recall | 欺诈 F1 |
|---|---|---|---|---|
| 训练集 | 0.9992 | 0.8897 | 0.6345 | 0.7407 |
| 测试集 | 0.9992 | 0.8228 | 0.6633 | 0.7345 |
测试集混淆矩阵:
| 指标 | 数值 |
|---|---|
| TN | 56850 |
| FP | 14 |
| FN | 33 |
| TP | 65 |
关键发现:
- Accuracy 99.92% 看起来极高,但 98 条欺诈仍漏掉 33 条(Recall=66.33%)
- 相比步骤 2 Always-Negative(Recall=0),LR 已能抓到大部分欺诈,但 FN 仍是业务痛点
- 不能只看 Accuracy:macro avg Recall 与 weighted avg Accuracy 差距大,说明少数类评估被「淹没」
- 14 条 FP:每约 4062 条正常交易中误报 1 条欺诈警报
4.9 为何 Accuracy 仍会误导?(Mermaid)
#mermaid-svg-pu23zzuAhu9P9ZGI{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-pu23zzuAhu9P9ZGI .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-pu23zzuAhu9P9ZGI .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-pu23zzuAhu9P9ZGI .error-icon{fill:#552222;}#mermaid-svg-pu23zzuAhu9P9ZGI .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-pu23zzuAhu9P9ZGI .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-pu23zzuAhu9P9ZGI .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-pu23zzuAhu9P9ZGI .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-pu23zzuAhu9P9ZGI .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-pu23zzuAhu9P9ZGI .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-pu23zzuAhu9P9ZGI .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-pu23zzuAhu9P9ZGI .marker{fill:#333333;stroke:#333333;}#mermaid-svg-pu23zzuAhu9P9ZGI .marker.cross{stroke:#333333;}#mermaid-svg-pu23zzuAhu9P9ZGI svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-pu23zzuAhu9P9ZGI p{margin:0;}#mermaid-svg-pu23zzuAhu9P9ZGI .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-pu23zzuAhu9P9ZGI .cluster-label text{fill:#333;}#mermaid-svg-pu23zzuAhu9P9ZGI .cluster-label span{color:#333;}#mermaid-svg-pu23zzuAhu9P9ZGI .cluster-label span p{background-color:transparent;}#mermaid-svg-pu23zzuAhu9P9ZGI .label text,#mermaid-svg-pu23zzuAhu9P9ZGI span{fill:#333;color:#333;}#mermaid-svg-pu23zzuAhu9P9ZGI .node rect,#mermaid-svg-pu23zzuAhu9P9ZGI .node circle,#mermaid-svg-pu23zzuAhu9P9ZGI .node ellipse,#mermaid-svg-pu23zzuAhu9P9ZGI .node polygon,#mermaid-svg-pu23zzuAhu9P9ZGI .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-pu23zzuAhu9P9ZGI .rough-node .label text,#mermaid-svg-pu23zzuAhu9P9ZGI .node .label text,#mermaid-svg-pu23zzuAhu9P9ZGI .image-shape .label,#mermaid-svg-pu23zzuAhu9P9ZGI .icon-shape .label{text-anchor:middle;}#mermaid-svg-pu23zzuAhu9P9ZGI .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-pu23zzuAhu9P9ZGI .rough-node .label,#mermaid-svg-pu23zzuAhu9P9ZGI .node .label,#mermaid-svg-pu23zzuAhu9P9ZGI .image-shape .label,#mermaid-svg-pu23zzuAhu9P9ZGI .icon-shape .label{text-align:center;}#mermaid-svg-pu23zzuAhu9P9ZGI .node.clickable{cursor:pointer;}#mermaid-svg-pu23zzuAhu9P9ZGI .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-pu23zzuAhu9P9ZGI .arrowheadPath{fill:#333333;}#mermaid-svg-pu23zzuAhu9P9ZGI .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-pu23zzuAhu9P9ZGI .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-pu23zzuAhu9P9ZGI .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-pu23zzuAhu9P9ZGI .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-pu23zzuAhu9P9ZGI .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-pu23zzuAhu9P9ZGI .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-pu23zzuAhu9P9ZGI .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-pu23zzuAhu9P9ZGI .cluster text{fill:#333;}#mermaid-svg-pu23zzuAhu9P9ZGI .cluster span{color:#333;}#mermaid-svg-pu23zzuAhu9P9ZGI div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-pu23zzuAhu9P9ZGI .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-pu23zzuAhu9P9ZGI rect.text{fill:none;stroke-width:0;}#mermaid-svg-pu23zzuAhu9P9ZGI .icon-shape,#mermaid-svg-pu23zzuAhu9P9ZGI .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-pu23zzuAhu9P9ZGI .icon-shape p,#mermaid-svg-pu23zzuAhu9P9ZGI .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-pu23zzuAhu9P9ZGI .icon-shape .label rect,#mermaid-svg-pu23zzuAhu9P9ZGI .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-pu23zzuAhu9P9ZGI .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-pu23zzuAhu9P9ZGI .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-pu23zzuAhu9P9ZGI :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} Accuracy 99.92%
56864 条正常几乎全对
98 条欺诈中漏 33 条
报表很好看
业务仍损失 33 笔欺诈
4.10 核心代码解读
(1)仅缩放 Amount
python
scaler = StandardScaler()
X_train["Amount"] = scaler.fit_transform(X_train[["Amount"]])
X_test["Amount"] = scaler.transform(X_test[["Amount"]])
V1~V28 来自 PCA 已近似标准化;Amount 原始量级不同,需单独 fit/transform。
(2)逻辑回归训练
python
model = LogisticRegression(max_iter=2000, random_state=42)
model.fit(X_train_scaled, y_train)
y_pred = model.predict(X_test_scaled) # 默认阈值 0.5
| 要点 | 说明 |
|---|---|
| 无 class_weight | 默认对多数类更「友好」 |
| max_iter=2000 | 28 万样本需更多迭代收敛 |
| predict | 概率 ≥0.5 判为欺诈(步骤 8 会调阈值) |
4.11 输出文件
| 文件 | 说明 |
|---|---|
reports/baseline_logistic_regression.txt |
基准 LR 指标报告 |
reports/figures/07_逻辑回归基准混淆矩阵.png |
测试集混淆矩阵热力图 |
4.12 动手任务
任务 A :运行脚本,确认测试 Accuracy ≈ 0.9992 、欺诈 Recall ≈ 0.66
任务 B:打开混淆矩阵图,找出 FN 和 FP 所在格子
任务 C:计算:若只报 Accuracy,会漏掉多少比例欺诈?(33/98 ≈ 33.7%)
任务 D:在 README 写:Precision 与 Recall 分别代表什么业务含义
4.13 验收标准
- 能解释混淆矩阵四格 TP/FP/TN/FN
- 能说出测试集 Accuracy 与欺诈 Recall 的数值
- 能解释为何 Accuracy 高仍可能漏报欺诈
- 知道本模型是后续 class_weight/SMOTE 的对比基准
4.14 常见问题
4.14 动手任务与验收标准参考答案
以下为教学标准答案,便于自学对照;
README.md学习记录仍建议用自己的话写。
动手任务答案
| 任务 | 参考答案 |
|---|---|
| A | Accuracy≈0.9992,Recall≈0.6633。 |
| B | TN=56850, FP=14, FN=33, TP=65。 |
| C | 漏报 33/98≈33.7%。 |
| D | Precision=误报相关;Recall=漏报相关。 |
验收标准答案
| 验收项 | 参考答案 |
|---|---|
| Acc/Recall | 见上。 |
| 混淆矩阵 | TN/FP/FN/TP 四格含义。 |
| Acc 高 Recall 一般 | 正常样本太多拉高 Acc。 |
| FN | 漏掉欺诈,银行承担损失。 |
Q:Recall 66% 算差吗?
A:比 Dummy(0%)好很多,但 33 笔漏报对银行仍是损失。步骤 5~8 会继续优化。
Q:为何不全特征 StandardScaler?
A:V1~V28 已是 PCA 变换结果,量纲已接近;本步按学习路线仅缩放 Amount。
Q:max_iter 警告怎么办?
A:已设为 2000。若仍警告可增大或使用 solver='saga'。
Q:下一步做什么?
A:步骤 5 使用 class_weight='balanced' 进一步提升欺诈 Recall。
4.15 本步小结
| 要点 | 内容 |
|---|---|
| 基准模型 | LogisticRegression(无 class_weight) |
| 测试 Accuracy | 0.9992 |
| 测试欺诈 Recall | 0.6633 |
| 漏报 FN | 33 / 98 条欺诈 |
| 下一步 | class_weight 平衡 |
4.16 学习记录(请你填写)
- 完成日期:
- 动手任务完成情况:任务 A / B / C / D
- 我对 Precision/Recall 的理解:
- 疑问(如有):
步骤 5:使用 class_weight 平衡
状态 :✅ 已完成教学(报告见
reports/class_weight_comparison.txt,图表见08_类别权重指标对比.png、09_逻辑回归类别权重混淆矩阵.png)
5.1 本步目标
- 理解
class_weight='balanced'是什么(用大白话说清楚) - 训练带类别权重的逻辑回归,与步骤 4 对比
- 观察 Recall 上升、Precision 下降 的典型权衡
- 理解:没有免费午餐,调权重要符合业务
5.2 这一步在解决什么问题?
步骤 4 的模型漏报 33 条欺诈。能不能让模型更积极抓欺诈?
class_weight='balanced' 的做法是:训练时告诉模型------「漏掉一条欺诈的代价,远大于误判一条正常」(通过给欺诈样本更大权重实现)。
本步要看:Recall 提高了多少?误报(FP)增加了多少?值不值得?
5.3 名词解释(通俗版)
| 名词 | 大白话 | 本步现象 |
|---|---|---|
| class_weight | 训练时给不同类别不同的「重视程度」 | balanced=自动加重欺诈 |
| balanced | sklearn 内置模式:样本越少,权重越大 | 欺诈仅 0.17%,权重很高 |
| Recall 召回率 | 100 条真欺诈里抓到了几条 | 66% → 92% |
| Precision 精确率 | 模型报警说「是欺诈」时,有几成真是 | 82% → 6% |
| 漏报 FN | 真欺诈却被放行 | 33 → 8 |
| 误报 FP | 正常交易却被拦 | 14 → 1416 |
5.4 class_weight 原理(Mermaid)
#mermaid-svg-MFdm94wIXU6Pk5qv{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-MFdm94wIXU6Pk5qv .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-MFdm94wIXU6Pk5qv .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-MFdm94wIXU6Pk5qv .error-icon{fill:#552222;}#mermaid-svg-MFdm94wIXU6Pk5qv .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-MFdm94wIXU6Pk5qv .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-MFdm94wIXU6Pk5qv .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-MFdm94wIXU6Pk5qv .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-MFdm94wIXU6Pk5qv .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-MFdm94wIXU6Pk5qv .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-MFdm94wIXU6Pk5qv .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-MFdm94wIXU6Pk5qv .marker{fill:#333333;stroke:#333333;}#mermaid-svg-MFdm94wIXU6Pk5qv .marker.cross{stroke:#333333;}#mermaid-svg-MFdm94wIXU6Pk5qv svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-MFdm94wIXU6Pk5qv p{margin:0;}#mermaid-svg-MFdm94wIXU6Pk5qv .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-MFdm94wIXU6Pk5qv .cluster-label text{fill:#333;}#mermaid-svg-MFdm94wIXU6Pk5qv .cluster-label span{color:#333;}#mermaid-svg-MFdm94wIXU6Pk5qv .cluster-label span p{background-color:transparent;}#mermaid-svg-MFdm94wIXU6Pk5qv .label text,#mermaid-svg-MFdm94wIXU6Pk5qv span{fill:#333;color:#333;}#mermaid-svg-MFdm94wIXU6Pk5qv .node rect,#mermaid-svg-MFdm94wIXU6Pk5qv .node circle,#mermaid-svg-MFdm94wIXU6Pk5qv .node ellipse,#mermaid-svg-MFdm94wIXU6Pk5qv .node polygon,#mermaid-svg-MFdm94wIXU6Pk5qv .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-MFdm94wIXU6Pk5qv .rough-node .label text,#mermaid-svg-MFdm94wIXU6Pk5qv .node .label text,#mermaid-svg-MFdm94wIXU6Pk5qv .image-shape .label,#mermaid-svg-MFdm94wIXU6Pk5qv .icon-shape .label{text-anchor:middle;}#mermaid-svg-MFdm94wIXU6Pk5qv .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-MFdm94wIXU6Pk5qv .rough-node .label,#mermaid-svg-MFdm94wIXU6Pk5qv .node .label,#mermaid-svg-MFdm94wIXU6Pk5qv .image-shape .label,#mermaid-svg-MFdm94wIXU6Pk5qv .icon-shape .label{text-align:center;}#mermaid-svg-MFdm94wIXU6Pk5qv .node.clickable{cursor:pointer;}#mermaid-svg-MFdm94wIXU6Pk5qv .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-MFdm94wIXU6Pk5qv .arrowheadPath{fill:#333333;}#mermaid-svg-MFdm94wIXU6Pk5qv .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-MFdm94wIXU6Pk5qv .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-MFdm94wIXU6Pk5qv .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-MFdm94wIXU6Pk5qv .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-MFdm94wIXU6Pk5qv .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-MFdm94wIXU6Pk5qv .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-MFdm94wIXU6Pk5qv .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-MFdm94wIXU6Pk5qv .cluster text{fill:#333;}#mermaid-svg-MFdm94wIXU6Pk5qv .cluster span{color:#333;}#mermaid-svg-MFdm94wIXU6Pk5qv div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-MFdm94wIXU6Pk5qv .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-MFdm94wIXU6Pk5qv rect.text{fill:none;stroke-width:0;}#mermaid-svg-MFdm94wIXU6Pk5qv .icon-shape,#mermaid-svg-MFdm94wIXU6Pk5qv .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-MFdm94wIXU6Pk5qv .icon-shape p,#mermaid-svg-MFdm94wIXU6Pk5qv .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-MFdm94wIXU6Pk5qv .icon-shape .label rect,#mermaid-svg-MFdm94wIXU6Pk5qv .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-MFdm94wIXU6Pk5qv .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-MFdm94wIXU6Pk5qv .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-MFdm94wIXU6Pk5qv :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 训练数据 正常占 99.8%
默认模型 倾向猜正常
class_weight balanced
欺诈样本权重变大
模型更愿预测欺诈
Recall 上升 FN 减少
Precision 下降 FP 增加
5.5 任务清单
- 训练
LogisticRegression(class_weight='balanced') - 与步骤 4 测试集指标对比表
- 对比 FN/FP 变化
- 保存
08_类别权重指标对比.png、09_逻辑回归类别权重混淆矩阵.png
5.6 运行本步
powershell
cd "d:\JavaCode\机器学习\project_02_fraud"
python src/train.py
5.7 实验结果(你的环境)
| 指标(测试集) | 步骤4 无权重 | 步骤5 balanced | 变化 |
|---|---|---|---|
| Accuracy | 0.9992 | 0.9750 | -0.0242 |
| 欺诈 Precision | 0.8228 | 0.0598 | -0.76 |
| 欺诈 Recall | 0.6633 | 0.9184 | +0.26 |
| 欺诈 F1 | 0.7345 | 0.1122 | -0.62 |
混淆矩阵变化:
| 步骤4 | 步骤5 | |
|---|---|---|
| 漏报 FN | 33 | 8 |
| 误报 FP | 14 | 1416 |
| 抓对 TP | 65 | 90 |
通俗解读:
- 好处:98 条欺诈里从抓到 65 条变成 90 条,漏报从 33 降到 8------银行少赔很多笔
- 代价:误报从 14 暴增到 1416------约每 40 笔正常交易就有 1 笔被误拦,用户体验很差
- Precision 只有 6%:模型喊 100 次「欺诈」,大约只有 6 次是对的
- 结论 :
balanced不是「一键变强」,而是把天平从「少误报」推向「少漏报」,必须结合业务选
5.8 业务怎么选?(Mermaid)
#mermaid-svg-e4p2zALeXaOsLkTx{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-e4p2zALeXaOsLkTx .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-e4p2zALeXaOsLkTx .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-e4p2zALeXaOsLkTx .error-icon{fill:#552222;}#mermaid-svg-e4p2zALeXaOsLkTx .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-e4p2zALeXaOsLkTx .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-e4p2zALeXaOsLkTx .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-e4p2zALeXaOsLkTx .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-e4p2zALeXaOsLkTx .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-e4p2zALeXaOsLkTx .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-e4p2zALeXaOsLkTx .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-e4p2zALeXaOsLkTx .marker{fill:#333333;stroke:#333333;}#mermaid-svg-e4p2zALeXaOsLkTx .marker.cross{stroke:#333333;}#mermaid-svg-e4p2zALeXaOsLkTx svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-e4p2zALeXaOsLkTx p{margin:0;}#mermaid-svg-e4p2zALeXaOsLkTx .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-e4p2zALeXaOsLkTx .cluster-label text{fill:#333;}#mermaid-svg-e4p2zALeXaOsLkTx .cluster-label span{color:#333;}#mermaid-svg-e4p2zALeXaOsLkTx .cluster-label span p{background-color:transparent;}#mermaid-svg-e4p2zALeXaOsLkTx .label text,#mermaid-svg-e4p2zALeXaOsLkTx span{fill:#333;color:#333;}#mermaid-svg-e4p2zALeXaOsLkTx .node rect,#mermaid-svg-e4p2zALeXaOsLkTx .node circle,#mermaid-svg-e4p2zALeXaOsLkTx .node ellipse,#mermaid-svg-e4p2zALeXaOsLkTx .node polygon,#mermaid-svg-e4p2zALeXaOsLkTx .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-e4p2zALeXaOsLkTx .rough-node .label text,#mermaid-svg-e4p2zALeXaOsLkTx .node .label text,#mermaid-svg-e4p2zALeXaOsLkTx .image-shape .label,#mermaid-svg-e4p2zALeXaOsLkTx .icon-shape .label{text-anchor:middle;}#mermaid-svg-e4p2zALeXaOsLkTx .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-e4p2zALeXaOsLkTx .rough-node .label,#mermaid-svg-e4p2zALeXaOsLkTx .node .label,#mermaid-svg-e4p2zALeXaOsLkTx .image-shape .label,#mermaid-svg-e4p2zALeXaOsLkTx .icon-shape .label{text-align:center;}#mermaid-svg-e4p2zALeXaOsLkTx .node.clickable{cursor:pointer;}#mermaid-svg-e4p2zALeXaOsLkTx .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-e4p2zALeXaOsLkTx .arrowheadPath{fill:#333333;}#mermaid-svg-e4p2zALeXaOsLkTx .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-e4p2zALeXaOsLkTx .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-e4p2zALeXaOsLkTx .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-e4p2zALeXaOsLkTx .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-e4p2zALeXaOsLkTx .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-e4p2zALeXaOsLkTx .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-e4p2zALeXaOsLkTx .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-e4p2zALeXaOsLkTx .cluster text{fill:#333;}#mermaid-svg-e4p2zALeXaOsLkTx .cluster span{color:#333;}#mermaid-svg-e4p2zALeXaOsLkTx div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-e4p2zALeXaOsLkTx .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-e4p2zALeXaOsLkTx rect.text{fill:none;stroke-width:0;}#mermaid-svg-e4p2zALeXaOsLkTx .icon-shape,#mermaid-svg-e4p2zALeXaOsLkTx .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-e4p2zALeXaOsLkTx .icon-shape p,#mermaid-svg-e4p2zALeXaOsLkTx .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-e4p2zALeXaOsLkTx .icon-shape .label rect,#mermaid-svg-e4p2zALeXaOsLkTx .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-e4p2zALeXaOsLkTx .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-e4p2zALeXaOsLkTx .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-e4p2zALeXaOsLkTx :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 更怕漏报欺诈
提高 Recall 方向
更怕误拦用户
提高 Precision 方向
class_weight / SMOTE / 降阈值
默认权重 / 升阈值
5.9 输出文件
| 文件 | 说明 |
|---|---|
reports/class_weight_comparison.txt |
前后对比报告 |
reports/figures/08_类别权重指标对比.png |
Precision/Recall/F1 对比 |
reports/figures/09_逻辑回归类别权重混淆矩阵.png |
步骤5 混淆矩阵 |
reports/figures/07_逻辑回归基准混淆矩阵.png |
步骤4 混淆矩阵(中文名) |
5.10 动手任务
任务 A :运行脚本,确认 Recall 从约 0.66 升到约 0.92
任务 B:看对比表,Precision 降到了多少?FP 增加了多少?
任务 C:用一句话说:银行更怕漏报还是更怕误报?你会选步骤4还是步骤5?
任务 D:在 README 记录你的选择理由
5.11 验收标准
- 能通俗解释 class_weight='balanced' 做什么
- 能说出 Recall 升、Precision 降的原因
- 能解释 FN 与 FP 的业务含义
- 知道没有绝对最优,要看业务容忍度
5.12 本步小结
5.12 动手任务与验收标准参考答案
以下为教学标准答案,便于自学对照;
README.md学习记录仍建议用自己的话写。
动手任务答案
| 任务 | 参考答案 |
|---|---|
| A | Recall 0.66→0.92。 |
| B | Precision→0.06;FP 14→1393。 |
| C | 更怕漏报;步骤 4 均衡、步骤 5 高 Recall 高误报。 |
| D | 按业务选:怕漏报选 5,怕误拦选 4。 |
验收标准答案
| 验收项 | 参考答案 |
|---|---|
| class_weight | 提高少数类权重,更倾向报欺诈。 |
| Recall↑ Precision↓ | 更激进报欺诈的结果。 |
| FN/FP | FN 漏欺诈;FP 误拦正常。 |
| 业务权衡 | 无绝对最优阈值/模型。 |
| 要点 | 内容 |
|---|---|
| 手段 | class_weight='balanced' |
| Recall | 0.66 → 0.92 |
| Precision | 0.82 → 0.06 |
| 漏报 FN | 33 → 8 |
| 误报 FP | 14 → 1416 |
| 教训 | 调权重是权衡,不是免费提升 |
| 下一步 | SMOTE(仅训练集) |
5.13 学习记录(请你填写)
- 完成日期:
- 我更能接受漏报还是误报:
- 疑问(如有):
步骤 6:SMOTE 过采样(仅训练集)
状态 :✅ 已完成教学(报告见
reports/smote_comparison.txt,图表见10_、11_、12_系列 PNG)
6.1 本步目标
- 理解 SMOTE 是什么(用大白话:怎么「造」欺诈样本)
- 只对训练集做 SMOTE,测试集保持原样
- 在 SMOTE 后的训练集上训练逻辑回归
- 对比步骤 4 / 5 / 6 三种做法谁更好
6.2 这一步在解决什么问题?
步骤 5 用 class_weight 加重欺诈的「话语权」,但训练集里欺诈仍然只有 394 条。
SMOTE 换一条路:在训练集里多造一些欺诈样本,让模型见更多欺诈长什么样。
关键规矩:只能在划分之后、只对训练集动手。如果对全量数据先 SMOTE 再划分,测试集信息就泄露了。
6.3 名词解释(通俗版)
| 名词 | 大白话 | 本步数据 |
|---|---|---|
| 过采样 | 让少数类样本变多 | 欺诈 394 → 227,451 |
| 欠采样 | 让多数类样本变少 | 本步不用 |
| SMOTE | 在两条真欺诈之间「插值」造新欺诈 | 合成约 227,057 条 |
| 合成样本 | 计算机算出来的假样本,不是真实交易 | 只存在于训练集 |
| 数据泄露 | 测试集信息混进训练 | 全量 SMOTE 再划分 = 错误 |
6.4 SMOTE 原理(Mermaid)
#mermaid-svg-jVQN442RNUEur49x{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-jVQN442RNUEur49x .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-jVQN442RNUEur49x .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-jVQN442RNUEur49x .error-icon{fill:#552222;}#mermaid-svg-jVQN442RNUEur49x .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-jVQN442RNUEur49x .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-jVQN442RNUEur49x .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-jVQN442RNUEur49x .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-jVQN442RNUEur49x .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-jVQN442RNUEur49x .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-jVQN442RNUEur49x .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-jVQN442RNUEur49x .marker{fill:#333333;stroke:#333333;}#mermaid-svg-jVQN442RNUEur49x .marker.cross{stroke:#333333;}#mermaid-svg-jVQN442RNUEur49x svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-jVQN442RNUEur49x p{margin:0;}#mermaid-svg-jVQN442RNUEur49x .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-jVQN442RNUEur49x .cluster-label text{fill:#333;}#mermaid-svg-jVQN442RNUEur49x .cluster-label span{color:#333;}#mermaid-svg-jVQN442RNUEur49x .cluster-label span p{background-color:transparent;}#mermaid-svg-jVQN442RNUEur49x .label text,#mermaid-svg-jVQN442RNUEur49x span{fill:#333;color:#333;}#mermaid-svg-jVQN442RNUEur49x .node rect,#mermaid-svg-jVQN442RNUEur49x .node circle,#mermaid-svg-jVQN442RNUEur49x .node ellipse,#mermaid-svg-jVQN442RNUEur49x .node polygon,#mermaid-svg-jVQN442RNUEur49x .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-jVQN442RNUEur49x .rough-node .label text,#mermaid-svg-jVQN442RNUEur49x .node .label text,#mermaid-svg-jVQN442RNUEur49x .image-shape .label,#mermaid-svg-jVQN442RNUEur49x .icon-shape .label{text-anchor:middle;}#mermaid-svg-jVQN442RNUEur49x .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-jVQN442RNUEur49x .rough-node .label,#mermaid-svg-jVQN442RNUEur49x .node .label,#mermaid-svg-jVQN442RNUEur49x .image-shape .label,#mermaid-svg-jVQN442RNUEur49x .icon-shape .label{text-align:center;}#mermaid-svg-jVQN442RNUEur49x .node.clickable{cursor:pointer;}#mermaid-svg-jVQN442RNUEur49x .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-jVQN442RNUEur49x .arrowheadPath{fill:#333333;}#mermaid-svg-jVQN442RNUEur49x .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-jVQN442RNUEur49x .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-jVQN442RNUEur49x .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-jVQN442RNUEur49x .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-jVQN442RNUEur49x .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-jVQN442RNUEur49x .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-jVQN442RNUEur49x .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-jVQN442RNUEur49x .cluster text{fill:#333;}#mermaid-svg-jVQN442RNUEur49x .cluster span{color:#333;}#mermaid-svg-jVQN442RNUEur49x div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-jVQN442RNUEur49x .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-jVQN442RNUEur49x rect.text{fill:none;stroke-width:0;}#mermaid-svg-jVQN442RNUEur49x .icon-shape,#mermaid-svg-jVQN442RNUEur49x .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-jVQN442RNUEur49x .icon-shape p,#mermaid-svg-jVQN442RNUEur49x .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-jVQN442RNUEur49x .icon-shape .label rect,#mermaid-svg-jVQN442RNUEur49x .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-jVQN442RNUEur49x .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-jVQN442RNUEur49x .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-jVQN442RNUEur49x :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 训练集里一条真欺诈 A
在 A 和 B 之间插值
训练集里另一条真欺诈 B
合成一条新欺诈
加入训练集再训练模型
测试集
绝不参与 SMOTE
不是:复制粘贴同一条欺诈 1000 遍(那叫重复采样,容易过拟合)。
6.5 正确 vs 错误流程(Mermaid)
#mermaid-svg-H7TAKO8HVj94b5A8{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-H7TAKO8HVj94b5A8 .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-H7TAKO8HVj94b5A8 .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-H7TAKO8HVj94b5A8 .error-icon{fill:#552222;}#mermaid-svg-H7TAKO8HVj94b5A8 .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-H7TAKO8HVj94b5A8 .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-H7TAKO8HVj94b5A8 .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-H7TAKO8HVj94b5A8 .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-H7TAKO8HVj94b5A8 .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-H7TAKO8HVj94b5A8 .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-H7TAKO8HVj94b5A8 .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-H7TAKO8HVj94b5A8 .marker{fill:#333333;stroke:#333333;}#mermaid-svg-H7TAKO8HVj94b5A8 .marker.cross{stroke:#333333;}#mermaid-svg-H7TAKO8HVj94b5A8 svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-H7TAKO8HVj94b5A8 p{margin:0;}#mermaid-svg-H7TAKO8HVj94b5A8 .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-H7TAKO8HVj94b5A8 .cluster-label text{fill:#333;}#mermaid-svg-H7TAKO8HVj94b5A8 .cluster-label span{color:#333;}#mermaid-svg-H7TAKO8HVj94b5A8 .cluster-label span p{background-color:transparent;}#mermaid-svg-H7TAKO8HVj94b5A8 .label text,#mermaid-svg-H7TAKO8HVj94b5A8 span{fill:#333;color:#333;}#mermaid-svg-H7TAKO8HVj94b5A8 .node rect,#mermaid-svg-H7TAKO8HVj94b5A8 .node circle,#mermaid-svg-H7TAKO8HVj94b5A8 .node ellipse,#mermaid-svg-H7TAKO8HVj94b5A8 .node polygon,#mermaid-svg-H7TAKO8HVj94b5A8 .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-H7TAKO8HVj94b5A8 .rough-node .label text,#mermaid-svg-H7TAKO8HVj94b5A8 .node .label text,#mermaid-svg-H7TAKO8HVj94b5A8 .image-shape .label,#mermaid-svg-H7TAKO8HVj94b5A8 .icon-shape .label{text-anchor:middle;}#mermaid-svg-H7TAKO8HVj94b5A8 .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-H7TAKO8HVj94b5A8 .rough-node .label,#mermaid-svg-H7TAKO8HVj94b5A8 .node .label,#mermaid-svg-H7TAKO8HVj94b5A8 .image-shape .label,#mermaid-svg-H7TAKO8HVj94b5A8 .icon-shape .label{text-align:center;}#mermaid-svg-H7TAKO8HVj94b5A8 .node.clickable{cursor:pointer;}#mermaid-svg-H7TAKO8HVj94b5A8 .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-H7TAKO8HVj94b5A8 .arrowheadPath{fill:#333333;}#mermaid-svg-H7TAKO8HVj94b5A8 .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-H7TAKO8HVj94b5A8 .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-H7TAKO8HVj94b5A8 .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-H7TAKO8HVj94b5A8 .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-H7TAKO8HVj94b5A8 .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-H7TAKO8HVj94b5A8 .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-H7TAKO8HVj94b5A8 .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-H7TAKO8HVj94b5A8 .cluster text{fill:#333;}#mermaid-svg-H7TAKO8HVj94b5A8 .cluster span{color:#333;}#mermaid-svg-H7TAKO8HVj94b5A8 div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-H7TAKO8HVj94b5A8 .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-H7TAKO8HVj94b5A8 rect.text{fill:none;stroke-width:0;}#mermaid-svg-H7TAKO8HVj94b5A8 .icon-shape,#mermaid-svg-H7TAKO8HVj94b5A8 .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-H7TAKO8HVj94b5A8 .icon-shape p,#mermaid-svg-H7TAKO8HVj94b5A8 .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-H7TAKO8HVj94b5A8 .icon-shape .label rect,#mermaid-svg-H7TAKO8HVj94b5A8 .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-H7TAKO8HVj94b5A8 .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-H7TAKO8HVj94b5A8 .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-H7TAKO8HVj94b5A8 :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 错误
全量 SMOTE
再划分
指标虚高
正确
划分 train/test
仅 train 做 SMOTE
fit 训练
predict 原 test
6.6 任务清单
-
SMOTE仅对X_train, y_train过采样 - SMOTE 后训练逻辑回归
- 在原始测试集上评估
- 对比步骤 4、5、6
- 保存中文文件名图表
6.7 运行本步
powershell
cd "d:\JavaCode\机器学习\project_02_fraud"
python src/train.py
注意:SMOTE 会把训练集扩到约 45 万条,首次运行可能需要 2~3 分钟。
6.8 实验结果(你的环境)
SMOTE 对训练集的影响:
| 阶段 | 正常 | 欺诈 |
|---|---|---|
| SMOTE 前 | 227,451 | 394 |
| SMOTE 后 | 227,451 | 227,451 |
| 合成欺诈 | --- | 约 227,057 条 |
三种方法测试集对比:
| 指标 | 步骤4 基准 | 步骤5 权重 | 步骤6 SMOTE |
|---|---|---|---|
| Accuracy | 0.9992 | 0.9754 | 0.9895 |
| 欺诈 Precision | 0.8228 | 0.0607 | 0.1309 |
| 欺诈 Recall | 0.6633 | 0.9184 | 0.9082 |
| 欺诈 F1 | 0.7345 | 0.1139 | 0.2288 |
步骤 6 混淆矩阵: FN=9(漏报),FP=591(误报),TP=89(抓对)
通俗解读:
- Recall 0.91:98 条欺诈抓到 89 条,只漏 9 条------漏报很少
- Precision 0.13:每喊 100 次「欺诈」约 13 次是对的------误报仍不少,但比步骤 5(6%)好
- 对比步骤 5:Recall 差不多,但 SMOTE 的 Precision 更高(13% vs 6%),误报 591 vs 1416
- 对比步骤 4:SMOTE Recall 更高,但 Precision 和 Accuracy 下降------又是权衡
- F1 最高仍是步骤 4:说明没有一招鲜,要看业务更怕漏报还是误报
6.9 三种方法怎么选?(Mermaid)
#mermaid-svg-P4bP2Gecu9eLVi1H{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-P4bP2Gecu9eLVi1H .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-P4bP2Gecu9eLVi1H .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-P4bP2Gecu9eLVi1H .error-icon{fill:#552222;}#mermaid-svg-P4bP2Gecu9eLVi1H .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-P4bP2Gecu9eLVi1H .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-P4bP2Gecu9eLVi1H .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-P4bP2Gecu9eLVi1H .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-P4bP2Gecu9eLVi1H .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-P4bP2Gecu9eLVi1H .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-P4bP2Gecu9eLVi1H .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-P4bP2Gecu9eLVi1H .marker{fill:#333333;stroke:#333333;}#mermaid-svg-P4bP2Gecu9eLVi1H .marker.cross{stroke:#333333;}#mermaid-svg-P4bP2Gecu9eLVi1H svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-P4bP2Gecu9eLVi1H p{margin:0;}#mermaid-svg-P4bP2Gecu9eLVi1H .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-P4bP2Gecu9eLVi1H .cluster-label text{fill:#333;}#mermaid-svg-P4bP2Gecu9eLVi1H .cluster-label span{color:#333;}#mermaid-svg-P4bP2Gecu9eLVi1H .cluster-label span p{background-color:transparent;}#mermaid-svg-P4bP2Gecu9eLVi1H .label text,#mermaid-svg-P4bP2Gecu9eLVi1H span{fill:#333;color:#333;}#mermaid-svg-P4bP2Gecu9eLVi1H .node rect,#mermaid-svg-P4bP2Gecu9eLVi1H .node circle,#mermaid-svg-P4bP2Gecu9eLVi1H .node ellipse,#mermaid-svg-P4bP2Gecu9eLVi1H .node polygon,#mermaid-svg-P4bP2Gecu9eLVi1H .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-P4bP2Gecu9eLVi1H .rough-node .label text,#mermaid-svg-P4bP2Gecu9eLVi1H .node .label text,#mermaid-svg-P4bP2Gecu9eLVi1H .image-shape .label,#mermaid-svg-P4bP2Gecu9eLVi1H .icon-shape .label{text-anchor:middle;}#mermaid-svg-P4bP2Gecu9eLVi1H .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-P4bP2Gecu9eLVi1H .rough-node .label,#mermaid-svg-P4bP2Gecu9eLVi1H .node .label,#mermaid-svg-P4bP2Gecu9eLVi1H .image-shape .label,#mermaid-svg-P4bP2Gecu9eLVi1H .icon-shape .label{text-align:center;}#mermaid-svg-P4bP2Gecu9eLVi1H .node.clickable{cursor:pointer;}#mermaid-svg-P4bP2Gecu9eLVi1H .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-P4bP2Gecu9eLVi1H .arrowheadPath{fill:#333333;}#mermaid-svg-P4bP2Gecu9eLVi1H .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-P4bP2Gecu9eLVi1H .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-P4bP2Gecu9eLVi1H .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-P4bP2Gecu9eLVi1H .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-P4bP2Gecu9eLVi1H .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-P4bP2Gecu9eLVi1H .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-P4bP2Gecu9eLVi1H .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-P4bP2Gecu9eLVi1H .cluster text{fill:#333;}#mermaid-svg-P4bP2Gecu9eLVi1H .cluster span{color:#333;}#mermaid-svg-P4bP2Gecu9eLVi1H div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-P4bP2Gecu9eLVi1H .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-P4bP2Gecu9eLVi1H rect.text{fill:none;stroke-width:0;}#mermaid-svg-P4bP2Gecu9eLVi1H .icon-shape,#mermaid-svg-P4bP2Gecu9eLVi1H .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-P4bP2Gecu9eLVi1H .icon-shape p,#mermaid-svg-P4bP2Gecu9eLVi1H .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-P4bP2Gecu9eLVi1H .icon-shape .label rect,#mermaid-svg-P4bP2Gecu9eLVi1H .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-P4bP2Gecu9eLVi1H .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-P4bP2Gecu9eLVi1H .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-P4bP2Gecu9eLVi1H :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 更怕漏报欺诈
步骤5 或 步骤6
更怕误拦用户
步骤4 基准
步骤6 SMOTE:Recall高且误报少于步骤5
6.10 输出文件
| 文件 | 说明 |
|---|---|
reports/smote_comparison.txt |
步骤 4/5/6 对比报告 |
reports/figures/10_SMOTE前后训练集对比.png |
过采样前后训练集数量 |
reports/figures/11_SMOTE逻辑回归混淆矩阵.png |
步骤 6 混淆矩阵 |
reports/figures/12_步骤456欺诈Recall对比.png |
三方法 Recall 对比 |
6.11 动手任务
任务 A :确认 SMOTE 后训练集欺诈约 227,451 条
任务 B:对比步骤 5 和 6 的 FP:谁误报更少?
任务 C:用一句话说明:为什么不能先 SMOTE 全量数据再划分?
任务 D:在 README 写:你更倾向步骤 4、5 还是 6?为什么?
6.12 验收标准
- 能通俗解释 SMOTE 在做什么
- 能说出 SMOTE 只作用于训练集
- 能对比步骤 4/5/6 的 Recall 与 Precision
- 知道合成样本有风险,必须用真实测试集验证
6.13 本步小结
6.13 动手任务与验收标准参考答案
以下为教学标准答案,便于自学对照;
README.md学习记录仍建议用自己的话写。
动手任务答案
| 任务 | 参考答案 |
|---|---|
| A | SMOTE 后训练欺诈约 227451。 |
| B | 步骤 6 FP=591 < 步骤 5 FP=1393。 |
| C | 全量 SMOTE 再划分会泄露。 |
| D | 倾向步骤 7 RF 或步骤 4 均衡。 |
验收标准答案
| 验收项 | 参考答案 |
|---|---|
| SMOTE | 插值合成少数类样本。 |
| 只作用于训练集 | 测试集保持真实分布。 |
| 4/5/6 对比 | Recall 与 Precision 此消彼长。 |
| 真实测试集 | 合成样本不能替代真实验证。 |
| 要点 | 内容 |
|---|---|
| 手段 | SMOTE 仅训练集 |
| 合成欺诈 | 约 227,057 条 |
| 测试 Recall | 0.9082 |
| 测试 Precision | 0.1309 |
| 漏报 FN | 9 / 98 |
| 教训 | 造样本能提 Recall,但要警惕误报与过拟合 |
| 下一步 | 随机森林 + ROC/PR 曲线 |
6.14 学习记录(请你填写)
- 完成日期:
- 我对 SMOTE 的理解:
- 疑问(如有):
步骤 7:换用树模型 Random Forest
状态 :✅ 已完成教学(报告见
reports/random_forest_comparison.txt,图表见13_~15_PNG)
7.1 本步目标
- 训练 随机森林 (100 棵树,
balanced_subsample) - 与逻辑回归最佳配置(
class_weight balanced)对比 - 画 ROC 曲线 与 PR 曲线,理解不平衡场景该看哪条
7.2 这一步在解决什么问题?
逻辑回归是「画一条直线」分两类。欺诈和正常的关系可能更复杂(非线性),树模型可以「切豆腐」一样分区判断。
本步还要回答一个常见困惑:ROC 很高 = 模型一定好吗? 在不平衡数据里,答案往往是「不一定」。
7.3 名词解释(通俗版)
| 名词 | 大白话 | 本步 |
|---|---|---|
| 随机森林 | 很多棵决策树投票,少数服从多数 | 100 棵树 |
| 决策树 | 一连串「如果...那么...」规则 | 森林的基本单元 |
| balanced_subsample | 每棵树训练时,对欺诈样本加大权重 | 类似 class_weight |
| ROC 曲线 | 横轴误报率、纵轴抓欺诈率,看整体区分力 | AUC 0.95 |
| PR 曲线 | 横轴 Recall、纵轴 Precision,更盯欺诈 | 更应看这条 |
| ROC-AUC | ROC 曲线下面积,0.5 瞎猜,1 完美 | LR 0.97,RF 0.95 |
| PR-AUC | PR 曲线下面积,不平衡时更有参考价值 | RF 0.86 > LR 0.72 |
7.4 为何不平衡时更看 PR?(Mermaid)
#mermaid-svg-qvIT3skki38QsdDP{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-qvIT3skki38QsdDP .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-qvIT3skki38QsdDP .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-qvIT3skki38QsdDP .error-icon{fill:#552222;}#mermaid-svg-qvIT3skki38QsdDP .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-qvIT3skki38QsdDP .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-qvIT3skki38QsdDP .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-qvIT3skki38QsdDP .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-qvIT3skki38QsdDP .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-qvIT3skki38QsdDP .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-qvIT3skki38QsdDP .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-qvIT3skki38QsdDP .marker{fill:#333333;stroke:#333333;}#mermaid-svg-qvIT3skki38QsdDP .marker.cross{stroke:#333333;}#mermaid-svg-qvIT3skki38QsdDP svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-qvIT3skki38QsdDP p{margin:0;}#mermaid-svg-qvIT3skki38QsdDP .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-qvIT3skki38QsdDP .cluster-label text{fill:#333;}#mermaid-svg-qvIT3skki38QsdDP .cluster-label span{color:#333;}#mermaid-svg-qvIT3skki38QsdDP .cluster-label span p{background-color:transparent;}#mermaid-svg-qvIT3skki38QsdDP .label text,#mermaid-svg-qvIT3skki38QsdDP span{fill:#333;color:#333;}#mermaid-svg-qvIT3skki38QsdDP .node rect,#mermaid-svg-qvIT3skki38QsdDP .node circle,#mermaid-svg-qvIT3skki38QsdDP .node ellipse,#mermaid-svg-qvIT3skki38QsdDP .node polygon,#mermaid-svg-qvIT3skki38QsdDP .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-qvIT3skki38QsdDP .rough-node .label text,#mermaid-svg-qvIT3skki38QsdDP .node .label text,#mermaid-svg-qvIT3skki38QsdDP .image-shape .label,#mermaid-svg-qvIT3skki38QsdDP .icon-shape .label{text-anchor:middle;}#mermaid-svg-qvIT3skki38QsdDP .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-qvIT3skki38QsdDP .rough-node .label,#mermaid-svg-qvIT3skki38QsdDP .node .label,#mermaid-svg-qvIT3skki38QsdDP .image-shape .label,#mermaid-svg-qvIT3skki38QsdDP .icon-shape .label{text-align:center;}#mermaid-svg-qvIT3skki38QsdDP .node.clickable{cursor:pointer;}#mermaid-svg-qvIT3skki38QsdDP .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-qvIT3skki38QsdDP .arrowheadPath{fill:#333333;}#mermaid-svg-qvIT3skki38QsdDP .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-qvIT3skki38QsdDP .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-qvIT3skki38QsdDP .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-qvIT3skki38QsdDP .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-qvIT3skki38QsdDP .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-qvIT3skki38QsdDP .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-qvIT3skki38QsdDP .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-qvIT3skki38QsdDP .cluster text{fill:#333;}#mermaid-svg-qvIT3skki38QsdDP .cluster span{color:#333;}#mermaid-svg-qvIT3skki38QsdDP div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-qvIT3skki38QsdDP .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-qvIT3skki38QsdDP rect.text{fill:none;stroke-width:0;}#mermaid-svg-qvIT3skki38QsdDP .icon-shape,#mermaid-svg-qvIT3skki38QsdDP .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-qvIT3skki38QsdDP .icon-shape p,#mermaid-svg-qvIT3skki38QsdDP .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-qvIT3skki38QsdDP .icon-shape .label rect,#mermaid-svg-qvIT3skki38QsdDP .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-qvIT3skki38QsdDP .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-qvIT3skki38QsdDP .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-qvIT3skki38QsdDP :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 99.8% 是正常交易
ROC 容易被正常样本拉高
PR 直接看欺诈抓得准不准
ROC 高可能虚胖
PR 更能反映风控效果
本步实例:
- 逻辑回归 ROC-AUC 0.97 > 随机森林 0.95(看起来 LR 更好?)
- 逻辑回归 PR-AUC 0.72 < 随机森林 0.86(PR 说明 RF 对欺诈更靠谱)
- 随机森林 Precision 96% (报欺诈时 96% 是对的),误报仅 3 条
7.5 任务清单
-
RandomForestClassifier(n_estimators=100, class_weight='balanced_subsample') - 与 LR balanced 对比指标与 AUC
- 绘制 ROC、PR 曲线(中文文件名)
- 保存混淆矩阵与报告
7.6 运行本步
powershell
cd "d:\JavaCode\机器学习\project_02_fraud"
python src/train.py
随机森林训练约 1~2 分钟(22 万样本 × 100 棵树)。
7.7 实验结果(你的环境)
| 指标(测试集) | LR balanced | 随机森林 |
|---|---|---|
| Accuracy | 0.9754 | 0.9995 |
| 欺诈 Precision | 0.0607 | 0.9600 |
| 欺诈 Recall | 0.9184 | 0.7347 |
| 欺诈 F1 | 0.1139 | 0.8324 |
| ROC-AUC | 0.9714 | 0.9529 |
| PR-AUC | 0.7153 | 0.8597 |
随机森林混淆矩阵: FN=26,FP=3,TP=72
通俗解读:
- 随机森林:误报极少(3 条),报欺诈时 96% 是对的,但漏报 26 条比 LR 多
- 逻辑回归 balanced:漏报少(Recall 92%),但误报 1416 条,Precision 只有 6%
- 业务选择:若不能接受误拦用户 → RF 更合适;若绝不能漏欺诈 → LR/SMOTE 更合适
- 看曲线 :ROC 两者都高,但 PR 曲线更能分出 RF 优势
7.8 输出文件
| 文件 | 说明 |
|---|---|
reports/random_forest_comparison.txt |
RF vs LR 对比报告 |
reports/figures/13_随机森林与逻辑回归ROC曲线.png |
ROC 对比 |
reports/figures/14_随机森林与逻辑回归PR曲线.png |
PR 对比 |
reports/figures/15_随机森林混淆矩阵.png |
RF 混淆矩阵 |
7.9 动手任务
任务 A:打开 PR 曲线图,哪条曲线更靠右上?
任务 B:为何 LR 的 ROC-AUC 更高,但 PR-AUC 更低?
任务 C:RF 只有 3 条误报,为什么 Recall 反而比 LR 低?
任务 D:在 README 写:你更愿意用 RF 还是 LR?为什么?
7.10 验收标准
- 能通俗解释随机森林是什么
- 能区分 ROC 与 PR 曲线各自关注什么
- 能说出「不平衡场景更应看 PR」的原因
- 能对比 RF 与 LR 的 Precision/Recall 权衡
7.11 本步小结
7.11 动手任务与验收标准参考答案
以下为教学标准答案,便于自学对照;
README.md学习记录仍建议用自己的话写。
动手任务答案
| 任务 | 参考答案 |
|---|---|
| A | RF PR 曲线更靠右上。 |
| B | ROC 受 TN 影响大;PR 看少数类,LR 抓欺诈不如 RF。 |
| C | RF Precision 96%、Recall 73%;更谨慎、少误报。 |
| D | 选 RF:误报仅 3 条。 |
验收标准答案
| 验收项 | 参考答案 |
|---|---|
| 随机森林 | 多树投票,非线性。 |
| ROC vs PR | 不平衡看 PR 更有参考价值。 |
| 不平衡看 PR | ROC 可能虚高。 |
| RF vs LR | RF P 高 R 中;LR balanced R 高 P 极低。 |
| 要点 | 内容 |
|---|---|
| 模型 | 随机森林 100 棵树 |
| 欺诈 Precision | 96%(误报 3 条) |
| 欺诈 Recall | 73.47%(漏报 26 条) |
| PR-AUC | 0.8597(优于 LR) |
| 教训 | ROC 高不等于欺诈抓得好,要看 PR |
| 下一步 | 阈值调优(步骤 8) |
7.12 学习记录(请你填写)
- 完成日期:
- 我对 ROC vs PR 的理解:
- 疑问(如有):
步骤 8:阈值调优
状态 :✅ 已完成教学(报告见
reports/threshold_tuning_report.txt,图表见16_~17_PNG)
8.1 本步目标
- 用
predict_proba得到欺诈概率(不是直接predict) - 扫描阈值 0.1~0.9,画 Precision / Recall / F1 曲线
- 对比 默认 0.5 与 F1 最优阈值,理解「业务旋钮」
8.2 这一步在解决什么问题?
步骤 7 的随机森林 Precision 很高(96%),但 Recall 只有 73%------漏了 26 条欺诈。
模型其实已经算出了「有多像欺诈」的概率,只是默认 ≥0.5 才报警 。如果把门槛降到 0.3,就会多抓一些欺诈,代价是多误报几条正常交易。
阈值 = 风控的松紧旋钮,不是机器学习里写死的 0.5。
8.3 名词解释(通俗版)
| 名词 | 大白话 | 本步 |
|---|---|---|
| predict_proba | 输出「是欺诈的概率」,如 0.37 | 扫描的基础 |
| 分类阈值 | 概率 ≥ 多少才判欺诈 | 默认 0.5,本步试 0.1~0.9 |
| 降低阈值 | 更容易报欺诈 | Recall↑,Precision↓ |
| 提高阈值 | 更谨慎才报欺诈 | Precision↑,Recall↓ |
| F1 最优 | 在 P 和 R 之间找折中点 | 本步选优策略(教学用) |
8.4 阈值如何影响预测?(Mermaid)
#mermaid-svg-CF6w7VLIvQLOcCix{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-CF6w7VLIvQLOcCix .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-CF6w7VLIvQLOcCix .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-CF6w7VLIvQLOcCix .error-icon{fill:#552222;}#mermaid-svg-CF6w7VLIvQLOcCix .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-CF6w7VLIvQLOcCix .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-CF6w7VLIvQLOcCix .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-CF6w7VLIvQLOcCix .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-CF6w7VLIvQLOcCix .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-CF6w7VLIvQLOcCix .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-CF6w7VLIvQLOcCix .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-CF6w7VLIvQLOcCix .marker{fill:#333333;stroke:#333333;}#mermaid-svg-CF6w7VLIvQLOcCix .marker.cross{stroke:#333333;}#mermaid-svg-CF6w7VLIvQLOcCix svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-CF6w7VLIvQLOcCix p{margin:0;}#mermaid-svg-CF6w7VLIvQLOcCix .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-CF6w7VLIvQLOcCix .cluster-label text{fill:#333;}#mermaid-svg-CF6w7VLIvQLOcCix .cluster-label span{color:#333;}#mermaid-svg-CF6w7VLIvQLOcCix .cluster-label span p{background-color:transparent;}#mermaid-svg-CF6w7VLIvQLOcCix .label text,#mermaid-svg-CF6w7VLIvQLOcCix span{fill:#333;color:#333;}#mermaid-svg-CF6w7VLIvQLOcCix .node rect,#mermaid-svg-CF6w7VLIvQLOcCix .node circle,#mermaid-svg-CF6w7VLIvQLOcCix .node ellipse,#mermaid-svg-CF6w7VLIvQLOcCix .node polygon,#mermaid-svg-CF6w7VLIvQLOcCix .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-CF6w7VLIvQLOcCix .rough-node .label text,#mermaid-svg-CF6w7VLIvQLOcCix .node .label text,#mermaid-svg-CF6w7VLIvQLOcCix .image-shape .label,#mermaid-svg-CF6w7VLIvQLOcCix .icon-shape .label{text-anchor:middle;}#mermaid-svg-CF6w7VLIvQLOcCix .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-CF6w7VLIvQLOcCix .rough-node .label,#mermaid-svg-CF6w7VLIvQLOcCix .node .label,#mermaid-svg-CF6w7VLIvQLOcCix .image-shape .label,#mermaid-svg-CF6w7VLIvQLOcCix .icon-shape .label{text-align:center;}#mermaid-svg-CF6w7VLIvQLOcCix .node.clickable{cursor:pointer;}#mermaid-svg-CF6w7VLIvQLOcCix .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-CF6w7VLIvQLOcCix .arrowheadPath{fill:#333333;}#mermaid-svg-CF6w7VLIvQLOcCix .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-CF6w7VLIvQLOcCix .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-CF6w7VLIvQLOcCix .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-CF6w7VLIvQLOcCix .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-CF6w7VLIvQLOcCix .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-CF6w7VLIvQLOcCix .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-CF6w7VLIvQLOcCix .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-CF6w7VLIvQLOcCix .cluster text{fill:#333;}#mermaid-svg-CF6w7VLIvQLOcCix .cluster span{color:#333;}#mermaid-svg-CF6w7VLIvQLOcCix div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-CF6w7VLIvQLOcCix .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-CF6w7VLIvQLOcCix rect.text{fill:none;stroke-width:0;}#mermaid-svg-CF6w7VLIvQLOcCix .icon-shape,#mermaid-svg-CF6w7VLIvQLOcCix .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-CF6w7VLIvQLOcCix .icon-shape p,#mermaid-svg-CF6w7VLIvQLOcCix .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-CF6w7VLIvQLOcCix .icon-shape .label rect,#mermaid-svg-CF6w7VLIvQLOcCix .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-CF6w7VLIvQLOcCix .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-CF6w7VLIvQLOcCix .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-CF6w7VLIvQLOcCix :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 是
否
predict_proba 欺诈概率
概率 >= 阈值?
预测:欺诈
预测:正常
阈值降低
更多 C,更少 D
Recall 升,Precision 降
阈值升高
更少 C,更多 D
Precision 升,Recall 降
8.5 任务清单
- 随机森林
predict_proba扫描 0.1~0.9(步长 0.01) - 绘制 Precision / Recall / F1 曲线(中文文件名)
- 对比默认 0.5 vs F1 最优阈值
- 保存最优阈值混淆矩阵与报告
8.6 运行本步
powershell
cd "d:\JavaCode\机器学习\project_02_fraud"
python src/train.py
需先训练随机森林(约 1~2 分钟),阈值扫描本身很快。
8.7 实验结果(你的环境)
| 指标(测试集) | 阈值 = 0.5(默认) | 阈值 = 0.30(F1 最优) |
|---|---|---|
| Accuracy | 0.9995 | 0.9996 |
| 欺诈 Precision | 0.9600 | 0.9318 |
| 欺诈 Recall | 0.7347 | 0.8367 |
| 欺诈 F1 | 0.8324 | 0.8817 |
| FN 漏报 | 26 | 16 |
| FP 误报 | 3 | 6 |
通俗解读:
- 把阈值从 0.5 降到 0.30 ,F1 从 0.83 提到 0.88
- 漏报从 26 条减到 16 条(多抓住 10 条欺诈)
- 误报从 3 条增到 6 条(多拦 3 条正常交易)------仍是可接受范围
- 业务含义:若银行「绝不能漏欺诈」,可继续降阈值;若「不能老误拦用户」,可维持 0.5 或更高
教学提醒 :在测试集上选最优阈值有「偷看答案」之嫌。真实项目应在验证集上选阈值,测试集只做最终验收。步骤 9 会保存推荐阈值。
8.8 输出文件
| 文件 | 说明 |
|---|---|
reports/threshold_tuning_report.txt |
阈值调优对比报告 |
reports/figures/16_随机森林阈值扫描PrecisionRecallF1曲线.png |
三指标随阈值变化 |
reports/figures/17_随机森林最优阈值混淆矩阵.png |
F1 最优阈值下的混淆矩阵 |
8.9 动手任务
任务 A:打开曲线图,0.5 附近三条线各在什么高度?
任务 B:若业务要求 Recall ≥ 90%,你会选大约多少阈值?(在图上找)
任务 C:为什么 F1 最优阈值是 0.30 而不是 0.50?
任务 D:写一句:你的银行更怕漏报还是误报?对应阈值该升还是降?
8.10 验收标准
- 能解释 predict 与 predict_proba 的区别
- 能说明降低/提高阈值对 P、R 的影响
- 能读懂阈值扫描曲线图
- 知道测试集调阈值的局限,验证集才更规范
8.11 本步小结
8.11 动手任务与验收标准参考答案
以下为教学标准答案,便于自学对照;
README.md学习记录仍建议用自己的话写。
动手任务答案
| 任务 | 参考答案 |
|---|---|
| A | 0.5 附近 P≈0.96,R≈0.73,F1≈0.83。 |
| B | Recall≥90% 阈值约 0.15~0.20。 |
| C | 0.30 时 F1 最高 0.8817,Recall 83.7% 且 P 仍 93%。 |
| D | 怕漏报降阈值;怕误报升阈值。 |
验收标准答案
| 验收项 | 参考答案 |
|---|---|
| predict/proba | 硬分类 vs 概率+自定义阈值。 |
| 阈值与 P/R | 降阈值 Recall↑ Precision↓。 |
| 阈值图 | F1 峰值在 0.30。 |
| 验证集选阈值 | 测试集选阈值有偷看答案之嫌。 |
| 要点 | 内容 |
|---|---|
| 模型 | 随机森林 + predict_proba |
| F1 最优阈值 | 0.30 |
| 最优 F1 | 0.8817(默认 0.5 为 0.8324) |
| 漏报 | 26 → 16(阈值降低) |
| 误报 | 3 → 6 |
| 下一步 | 项目总结与保存模型(步骤 9) |
8.12 学习记录(请你填写)
- 完成日期:
- 我选的「业务阈值」及理由:
- 疑问(如有):
步骤 9:项目总结
状态 :✅ 已完成教学(报告见
reports/final_project_summary.txt,模型见models/fraud_best.pkl)
9.1 本步目标
- 汇总步骤 4~8 全部代表实验
- 选定最终推荐模型与阈值
- 用
joblib保存模型 + scaler + 阈值 - 写出 3 个关键教训与预期业务效果
9.2 这一步在解决什么问题?
前面各步试了很多方法,最后要回答三个问题:
- 用哪个模型上线?
- 阈值设多少?
- 预期能抓住多少欺诈、误拦多少正常交易?
9.3 名词解释(通俗版)
| 名词 | 大白话 | 本步 |
|---|---|---|
| joblib.dump | 把 Python 对象(模型)存成文件 | models/fraud_best.pkl |
| bundle | 打包:模型 + scaler + 阈值 + 元数据 | 加载一次即可推理 |
| 配置文件 | 记录推荐阈值与加载示例 | fraud_model_config.txt |
9.4 全部实验回顾(Mermaid)
#mermaid-svg-zKAt5V8mMK55MmHy{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-zKAt5V8mMK55MmHy .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-zKAt5V8mMK55MmHy .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-zKAt5V8mMK55MmHy .error-icon{fill:#552222;}#mermaid-svg-zKAt5V8mMK55MmHy .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-zKAt5V8mMK55MmHy .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-zKAt5V8mMK55MmHy .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-zKAt5V8mMK55MmHy .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-zKAt5V8mMK55MmHy .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-zKAt5V8mMK55MmHy .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-zKAt5V8mMK55MmHy .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-zKAt5V8mMK55MmHy .marker{fill:#333333;stroke:#333333;}#mermaid-svg-zKAt5V8mMK55MmHy .marker.cross{stroke:#333333;}#mermaid-svg-zKAt5V8mMK55MmHy svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-zKAt5V8mMK55MmHy p{margin:0;}#mermaid-svg-zKAt5V8mMK55MmHy .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-zKAt5V8mMK55MmHy .cluster-label text{fill:#333;}#mermaid-svg-zKAt5V8mMK55MmHy .cluster-label span{color:#333;}#mermaid-svg-zKAt5V8mMK55MmHy .cluster-label span p{background-color:transparent;}#mermaid-svg-zKAt5V8mMK55MmHy .label text,#mermaid-svg-zKAt5V8mMK55MmHy span{fill:#333;color:#333;}#mermaid-svg-zKAt5V8mMK55MmHy .node rect,#mermaid-svg-zKAt5V8mMK55MmHy .node circle,#mermaid-svg-zKAt5V8mMK55MmHy .node ellipse,#mermaid-svg-zKAt5V8mMK55MmHy .node polygon,#mermaid-svg-zKAt5V8mMK55MmHy .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-zKAt5V8mMK55MmHy .rough-node .label text,#mermaid-svg-zKAt5V8mMK55MmHy .node .label text,#mermaid-svg-zKAt5V8mMK55MmHy .image-shape .label,#mermaid-svg-zKAt5V8mMK55MmHy .icon-shape .label{text-anchor:middle;}#mermaid-svg-zKAt5V8mMK55MmHy .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-zKAt5V8mMK55MmHy .rough-node .label,#mermaid-svg-zKAt5V8mMK55MmHy .node .label,#mermaid-svg-zKAt5V8mMK55MmHy .image-shape .label,#mermaid-svg-zKAt5V8mMK55MmHy .icon-shape .label{text-align:center;}#mermaid-svg-zKAt5V8mMK55MmHy .node.clickable{cursor:pointer;}#mermaid-svg-zKAt5V8mMK55MmHy .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-zKAt5V8mMK55MmHy .arrowheadPath{fill:#333333;}#mermaid-svg-zKAt5V8mMK55MmHy .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-zKAt5V8mMK55MmHy .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-zKAt5V8mMK55MmHy .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-zKAt5V8mMK55MmHy .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-zKAt5V8mMK55MmHy .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-zKAt5V8mMK55MmHy .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-zKAt5V8mMK55MmHy .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-zKAt5V8mMK55MmHy .cluster text{fill:#333;}#mermaid-svg-zKAt5V8mMK55MmHy .cluster span{color:#333;}#mermaid-svg-zKAt5V8mMK55MmHy div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-zKAt5V8mMK55MmHy .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-zKAt5V8mMK55MmHy rect.text{fill:none;stroke-width:0;}#mermaid-svg-zKAt5V8mMK55MmHy .icon-shape,#mermaid-svg-zKAt5V8mMK55MmHy .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-zKAt5V8mMK55MmHy .icon-shape p,#mermaid-svg-zKAt5V8mMK55MmHy .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-zKAt5V8mMK55MmHy .icon-shape .label rect,#mermaid-svg-zKAt5V8mMK55MmHy .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-zKAt5V8mMK55MmHy .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-zKAt5V8mMK55MmHy .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-zKAt5V8mMK55MmHy :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 步骤4 LR基准
步骤5 class_weight
步骤6 SMOTE
步骤7 随机森林
步骤8 阈值调优
步骤9 最终推荐
RandomForest + 阈值 0.30
9.5 任务清单
- 汇总步骤 4~8 测试集 Precision / Recall / F1
- 绘制全部方法 F1 对比图
- 写最终结论与 3 个关键教训
-
joblib保存 bundle + 阈值配置说明
9.6 运行本步
powershell
cd "d:\JavaCode\机器学习\project_02_fraud"
python src/train.py
会重新训练全部代表模型(含 SMOTE),约 3~5 分钟。
9.7 全部实验结果(测试集)
| 方法 | 阈值 | Precision | Recall | F1 |
|---|---|---|---|---|
| 步骤4 LR基准 | 0.50 | 0.8228 | 0.6633 | 0.7345 |
| 步骤5 LR balanced | 0.50 | 0.0607 | 0.9184 | 0.1139 |
| 步骤6 SMOTE+LR | 0.50 | 0.1309 | 0.9082 | 0.2288 |
| 步骤7 随机森林 | 0.50 | 0.9600 | 0.7347 | 0.8324 |
| 步骤8 RF阈值0.30 | 0.30 | 0.9318 | 0.8367 | 0.8817 |
9.8 最终推荐
| 项目 | 内容 |
|---|---|
| 推荐模型 | RandomForest(100 棵树,balanced_subsample) |
| 推荐阈值 | 0.30 |
| 欺诈 Recall | 83.67%(98 条里抓住 82 条) |
| 欺诈 Precision | 93.18%(100 次警报约 93 次是真欺诈) |
| 漏报 FN | 16 条 |
| 误报 FP | 6 条 |
通俗业务效果:
- 比默认 0.5 阈值多抓 10 条 欺诈,只多误拦 3 条正常交易
- 若银行「绝不能漏欺诈」→ 可继续降阈值(Recall 更高,误报更多)
- 若银行「不能老误拦用户」→ 可维持 0.5 或更高阈值
9.9 本项目 3 个关键教训
- Accuracy 会误导:全猜正常也能 99.83%,必须看欺诈 Recall 与 FN
- 不平衡更看 PR:ROC 高不一定抓欺诈好,要看 PR 曲线与 Precision/Recall
- 阈值是业务旋钮:模型给概率,风控决定松紧;0.5 不是唯一答案
9.10 输出文件
| 文件 | 说明 |
|---|---|
reports/final_project_summary.txt |
全部实验汇总与结论 |
reports/fraud_model_config.txt |
推荐阈值与加载示例 |
reports/figures/18_全部方法欺诈F1对比.png |
各方法 F1 对比 |
models/fraud_best.pkl |
joblib 模型 bundle(本地生成,Git 不提交) |
9.11 加载模型示例
python
import joblib
import pandas as pd
# 加载打包好的 bundle
bundle = joblib.load("models/fraud_best.pkl")
# 准备与训练相同 30 列特征
X = pd.read_csv("data/creditcard.csv").drop(columns=["Class"])
# 复制一份用于缩放 Amount
X_scaled = X.copy()
# 用 bundle 内 scaler 变换 Amount
X_scaled["Amount"] = bundle["scaler"].transform(X[["Amount"]])
# 欺诈概率
proba = bundle["model"].predict_proba(X_scaled)[:, 1]
# 按推荐阈值判欺诈
pred = (proba >= bundle["threshold"]).astype(int)
9.12 动手任务
任务 A:为什么最终选随机森林而不是 LR balanced(Recall 更高)?
任务 B:若要求 Recall ≥ 90%,你会把阈值调到多少?
任务 C:在 README 写一句:本项目对你最大的收获是什么?
9.13 验收标准
- 能说出最终推荐模型与阈值
- 能用一句话描述预期业务效果
- 能复述 3 个关键教训
- 知道如何用 joblib 加载 bundle 推理
9.14 本步小结
9.14 动手任务与验收标准参考答案
以下为教学标准答案,便于自学对照;
README.md学习记录仍建议用自己的话写。
动手任务答案
| 任务 | 参考答案 |
|---|---|
| A | RF+0.30 综合 F1/P/FP 优于 LR balanced。 |
| B | Recall≥90% 阈值约 0.15~0.20。 |
| C | 示例:学会不看 Accuracy,看 Recall 与阈值。 |
验收标准答案
| 验收项 | 参考答案 |
|---|---|
| 最终推荐 | RandomForest + 阈值 0.30。 |
| 业务效果 | 抓 83.7% 欺诈,误报 6 条。 |
| 3 教训 | Accuracy 误导;看 PR;proba+阈值=策略。 |
| joblib | load bundle → scaler → predict_proba → 阈值。 |
| 要点 | 内容 |
|---|---|
| 最终模型 | 随机森林 + 阈值 0.30 |
| 测试 F1 | 0.8817(全部方法最高) |
| 保存 | models/fraud_best.pkl |
| 状态 | 项目二 9 步全部完成 |
9.15 学习记录(请你填写)
- 完成日期:
- 我若上线会选什么阈值及理由:
- 最大收获:
文档版本:v1.9 | 最后更新:全步骤动手任务与验收标准参考答案已补充