项目二教学文档:信用卡欺诈检测 —— 不平衡分类

项目二教学文档:信用卡欺诈检测 ------ 不平衡分类

https://gitee.com/ghaweiuptgb/machine-learning-AI.git (代码包)

使用说明 :本文档是项目二的完整教学记录。每完成一个步骤,我会把该步骤的详细教学过程写入对应章节。

配套文件

代码规范 :逐行注释 + 图表中文(见根目录 .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 本步目标

  1. 创建 project_02_fraud/ 目录结构(与项目一一致)
  2. 下载并加载 Credit Card Fraud Detection 数据集
  3. 安装 imbalanced-learn(后续 SMOTE 需要)
  4. 运行 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.csvdata/
  • 安装 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 本步目标

  1. 量化 Class 分布,直观感受欺诈占比极低
  2. 计算 Always-Negative 基线(全预测正常)的 Accuracy
  3. 绘制 Amount 原始分布与 log1p 变换后分布
  4. 理解为何 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 任务清单

  • 打印 Classvalue_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 :比较 0203 两张 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 本步目标

  1. 使用 train_test_split(..., stratify=y) 做 80/20 划分
  2. 理解 stratify 如何保持训练/测试中欺诈比例与全集一致
  3. 明确 数据泄露 边界:先划分,再(仅对训练集)过采样

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 本步目标

  1. StandardScaler 缩放 Amount(V1~V28 已是 PCA 结果,保持原样)
  2. 训练 LogisticRegression 作为第一个真实分类模型(无 class_weight)
  3. 输出 Accuracy、Precision、Recall、F1classification_report
  4. 绘制混淆矩阵热力图,理解 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_类别权重指标对比.png09_逻辑回归类别权重混淆矩阵.png

5.1 本步目标

  1. 理解 class_weight='balanced' 是什么(用大白话说清楚)
  2. 训练带类别权重的逻辑回归,与步骤 4 对比
  3. 观察 Recall 上升、Precision 下降 的典型权衡
  4. 理解:没有免费午餐,调权重要符合业务

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_类别权重指标对比.png09_逻辑回归类别权重混淆矩阵.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 本步目标

  1. 理解 SMOTE 是什么(用大白话:怎么「造」欺诈样本)
  2. 只对训练集做 SMOTE,测试集保持原样
  3. 在 SMOTE 后的训练集上训练逻辑回归
  4. 对比步骤 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 本步目标

  1. 训练 随机森林 (100 棵树,balanced_subsample
  2. 与逻辑回归最佳配置(class_weight balanced)对比
  3. 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 本步目标

  1. predict_proba 得到欺诈概率(不是直接 predict
  2. 扫描阈值 0.1~0.9,画 Precision / Recall / F1 曲线
  3. 对比 默认 0.5F1 最优阈值,理解「业务旋钮」

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 本步目标

  1. 汇总步骤 4~8 全部代表实验
  2. 选定最终推荐模型与阈值
  3. joblib 保存模型 + scaler + 阈值
  4. 写出 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 个关键教训

  1. Accuracy 会误导:全猜正常也能 99.83%,必须看欺诈 Recall 与 FN
  2. 不平衡更看 PR:ROC 高不一定抓欺诈好,要看 PR 曲线与 Precision/Recall
  3. 阈值是业务旋钮:模型给概率,风控决定松紧;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 | 最后更新:全步骤动手任务与验收标准参考答案已补充