时序分类常用衡量指标
下面将会讲解混淆矩阵、分类指标(准确率、精确率、召回率、F1 分数)、类别分布,以及 AUROC 和 AUPRC 等指标。
# 🔹 第一步:混淆矩阵(Confusion Matrix)
# 📌 一、什么是混淆矩阵?
混淆矩阵是用于评估分类模型效果的核心工具。它详细展示了模型在每种预测与实际组合上的表现。
最常见的是二分类混淆矩阵,是一个 2×2 表格:
实际\预测 | 预测为正类(1) | 预测为负类(0) |
---|---|---|
实际是正类(1) | ✅ True Positive(TP) | ❌ False Negative(FN) |
实际是负类(0) | ❌ False Positive(FP) | ✅ True Negative(TN) |
# 📊 二、解释每个部分的含义
名称 | 缩写 | 解释(直观理解) |
---|---|---|
True Positive | TP | 模型说是“正类”,实际也是“正类” ✔️ |
False Positive | FP | 模型说是“正类”,但其实是“负类”(误报) ❌ |
False Negative | FN | 模型说是“负类”,但其实是“正类”(漏报) ❌ |
True Negative | TN | 模型说是“负类”,实际也是“负类” ✔️ |
# 📘 三、案例演示(直观理解)
假设你在做癌症筛查:
实际\预测 | 预测“有癌” | 预测“无癌” |
---|---|---|
实际“有癌” | TP = 10 | FN = 2 |
实际“无癌” | FP = 5 | TN = 83 |
说明:
- 模型发现了 10 个真的癌症(TP)
- 漏掉了 2 个有癌的(FN)→ 很严重!
- 误报了 5 个没癌的为有癌(FP)→ 会造成病人焦虑
- 正确识别了 83 个健康人(TN)
# 🧮 四、Python 中如何生成混淆矩阵?
from sklearn.metrics import confusion_matrix
# 假设真实标签和预测标签如下:
y_true = [1, 0, 1, 0, 1, 0, 0, 1]
y_pred = [1, 0, 0, 0, 1, 0, 1, 0]
cm = confusion_matrix(y_true, y_pred)
print(cm)
2
3
4
5
6
7
8
输出:
[[3 1] # 实际是 0(负类):3 个预测对了(TN),1 个误报(FP)
[2 2]] # 实际是 1(正类):2 个漏报(FN),2 个预测对了(TP)
2
# 📌 五、为什么混淆矩阵重要?
它是所有分类指标的基础(accuracy、precision、recall、F1 等都来自它)
它能告诉你模型到底哪里错了:
- 是误报太多?(FP)
- 是漏报太多?(FN)
在不平衡数据中尤其重要:accuracy 很高,但可能全是 FP 和 FN。
# 📈 六、可视化(使用 heatmap 更直观)
import seaborn as sns
import matplotlib.pyplot as plt
sns.heatmap(cm, annot=True, fmt="d", cmap="Blues",
xticklabels=["Pred 0", "Pred 1"],
yticklabels=["True 0", "True 1"])
plt.xlabel("Predicted")
plt.ylabel("Actual")
plt.title("Confusion Matrix")
plt.show()
2
3
4
5
6
7
8
9
10
# ✅ 小结
知识点 | 解释 |
---|---|
TP、TN、FP、FN | 四个基本元素,决定模型表现 |
混淆矩阵 | 可视化地展示模型在哪些预测对/错了 |
后续指标 | 全部基于混淆矩阵来计算(下一步会讲) |
# 🔹 第二步:分类指标(Accuracy、Precision、Recall、F1-score)
# 📌 一、为什么需要这些指标?
虽然混淆矩阵很清晰,但不方便对比模型。我们用几个汇总指标从不同角度衡量模型性能,尤其是在类别不平衡时。
# 🧮 二、指标计算公式和解释
我们先回顾一下混淆矩阵四项:
- TP:预测为正,实际为正(真正)
- TN:预测为负,实际为负(真负)
- FP:预测为正,实际为负(假正 / 误报)
- FN:预测为负,实际为正(假负 / 漏报)
# ✅ 1. 准确率(Accuracy)
- 衡量模型总共预测对了多少。
- 适用于类别平衡场景。
- ⚠️ 在类别极不平衡时会误导(例如全预测为多数类也很高)。
# ✅ 2. 精确率(Precision)
- 预测为正的样本中,实际正的有多少?
- 精确率高 → 不误报。
- 适合关注“不冤枉人”的场景(如垃圾邮件识别、肿瘤检测)。
# ✅ 3. 召回率(Recall)
- 所有实际为正的样本中,成功预测为正的比例。
- 召回率高 → 不漏报。
- 适合关注“不能漏掉”的场景(如癌症筛查、安全预警)。
# ✅ 4. F1-score(调和平均)
- 精确率和召回率的综合指标
- 偏低的一方会拉低 F1(比平均数更保守)
- 适合平衡误报和漏报的场景
# 📘 三、具体例子演算
假设你有以下混淆矩阵:
实际 \ 预测 | 预测为 1 | 预测为 0 |
---|---|---|
实际为 1 | TP = 30 | FN = 20 |
实际为 0 | FP = 10 | TN = 40 |
代入公式:
- Accuracy = (30 + 40) / (30 + 20 + 10 + 40) = 70 / 100 = 0.70
- Precision = 30 / (30 + 10) = 30 / 40 = 0.75
- Recall = 30 / (30 + 20) = 30 / 50 = 0.60
- F1 = 2 × (0.75 × 0.6) / (0.75 + 0.6) ≈ 0.6667
# 🧠 四、sklearn 中如何计算这些指标?
from sklearn.metrics import precision_score, recall_score, f1_score, accuracy_score
y_true = [1, 1, 1, 0, 0, 0, 1, 0, 0, 1]
y_pred = [1, 0, 1, 0, 0, 0, 0, 1, 0, 1]
print("Accuracy:", accuracy_score(y_true, y_pred))
print("Precision:", precision_score(y_true, y_pred))
print("Recall:", recall_score(y_true, y_pred))
print("F1 Score:", f1_score(y_true, y_pred))
'''输出
Accuracy: 0.7
Precision: 0.75
Recall: 0.6
F1 Score: 0.6666666666666666
'''
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
# ✅ 小结:指标适用场景
指标 | 关注点 | 场景示例 |
---|---|---|
Accuracy | 总体正确率 | 类别平衡时使用 |
Precision | 不冤枉人 | 肿瘤检测、刑事侦查 |
Recall | 不漏掉人 | 疾病筛查、故障检测 |
F1-score | 平衡两者 | 新闻分类、情感分析等常规任务 |
# 🔹 第三步:分类报告(Classification Report)详解
# 📌 一、什么是分类报告?
在实际中,我们往往不只是看单个指标,而是希望按类别全面了解模型表现。
分类报告是由 sklearn.metrics.classification_report()
自动生成的一个评估摘要表:
# 👇 格式如下(示例):
precision recall f1-score support
0 0.90 0.95 0.92 1000
1 0.85 0.70 0.77 200
accuracy 0.89 1200
macro avg 0.87 0.83 0.85 1200
weighted avg 0.89 0.89 0.89 1200
2
3
4
5
6
7
# 📊 二、每列指标含义回顾
列名 | 含义 |
---|---|
precision | 本类预测中有多少是真的(TP / (TP + FP)) |
recall | 实际本类中你找出多少(TP / (TP + FN)) |
f1-score | 精确率和召回率的调和平均 |
support | 实际中这个类有多少样本(即真实标签中这个类的样本数) |
# 🧠 三、底部的平均项解释
在多分类任务或不平衡数据中,我们还会看到这几项平均指标:
名称 | 含义 |
---|---|
accuracy | 所有预测正确的样本占总样本比例(全局准确率) |
macro avg | 对每个类别的 precision/recall/F1 分别求平均,不考虑类频率 |
weighted avg | 对每个类别的指标按 support 加权平均,适用于不平衡分类 |
micro avg | 先对所有 TP/FP/FN 总计再计算指标,适用于多标签任务(可选) |
# 🎯 四、例子(手动构造)
假设模型对两类结果如下:
类别 | Precision | Recall | F1-score | Support |
---|---|---|---|---|
0 | 0.95 | 0.90 | 0.925 | 1000 |
1 | 0.70 | 0.80 | 0.747 | 200 |
# 1️⃣ macro average(不考虑类别数量):
# 2️⃣ weighted average(按样本数加权):
# ⚙️ 五、在代码中生成分类报告
from sklearn.metrics import classification_report
y_true = [0, 0, 0, 1, 1, 1, 1]
y_pred = [0, 0, 1, 0, 1, 1, 1]
print(classification_report(y_true, y_pred))
2
3
4
5
6
输出类似:
precision recall f1-score support
0 0.67 0.67 0.67 3
1 0.75 0.75 0.75 4
accuracy 0.71 7
macro avg 0.71 0.71 0.71 7
weighted avg 0.71 0.71 0.71 7
2
3
4
5
6
7
# 🔍 六、实战建议
- 看 macro avg:适合对每个类都关注的任务,如医学诊断中不同病种都很重要;
- 看 weighted avg:适合不平衡数据,尤其是生产环境;
- 看 per-class 指标:找出模型偏向了哪个类,哪个类识别不好;
- 看 support:小类 recall 不高很可能是样本不够 → 需要数据增强或采样策略;
# ✅ 总结:分类报告可以让你一眼看出
- 哪些类识别得好 / 哪些类被严重忽视(recall 低)
- 是否存在偏向某个类的倾向(精确率高、召回低)
- 模型总体表现是否受类别不平衡影响(macro vs weighted)
# 🔹 第四步:类别分布(Class Imbalance)及其影响与对策
# 📌 一、什么是类别不平衡(Class Imbalance)?
类别不平衡是指数据集中某些类别的样本数量远大于其他类别。
比如在一个“欺诈交易识别”任务中:
- 类别 0(正常交易)有 99,000 条
- 类别 1(欺诈交易)只有 1,000 条
👉 比例是 99:1,就是一个典型的极度不平衡二分类问题。
# 📉 二、类别不平衡带来的问题
# 🚫 问题 1:Accuracy 被“虚高”
一个模型如果全预测为多数类(0),它的准确率依然很高:
实际上,它没有识别出一个欺诈交易!
# 🚫 问题 2:Recall、Precision 等失衡
- 模型往往学习“偏向”多数类,忽略少数类
- 少数类的 Recall 非常低(几乎没能找出来)
- 有些模型会预测成 0 的概率极高,导致 AUROC 看起来好看,但 AUPRC 很差
# 📊 三、如何检测类别分布?
可以用 Counter
或 value_counts()
:
from collections import Counter
y = [0]*9900 + [1]*100
print(Counter(y))
# 输出: Counter({0: 9900, 1: 100})
2
3
4
5
或 pandas:
import pandas as pd
df['label'].value_counts(normalize=True) # 查看比例
2
# 🛠 四、如何应对类别不平衡?
我们从数据层面和模型层面提供策略:
# ✅ A. 数据层面方法
# 1. 欠采样(Under-sampling)
- 随机去掉一部分多数类样本,让其与少数类平衡。
- 适用于数据总量大、训练代价高时。
from imblearn.under_sampling import RandomUnderSampler
rus = RandomUnderSampler()
X_res, y_res = rus.fit_resample(X, y)
2
3
4
# 2. 过采样(Over-sampling)
- 复制或合成少数类样本,提高其数量。
- 典型方法:SMOTE(合成少数类样本)
from imblearn.over_sampling import SMOTE
sm = SMOTE()
X_res, y_res = sm.fit_resample(X, y)
2
3
4
# ✅ B. 模型层面方法
# 1. 调整损失函数中的权重
- 给少数类更高的权重,让模型“重视”它:
from sklearn.linear_model import LogisticRegression
model = LogisticRegression(class_weight='balanced')
2
或在 PyTorch 中:
loss_fn = nn.CrossEntropyLoss(weight=torch.tensor([0.2, 0.8]))
# 2. 使用专门为不平衡设计的模型
- 如 XGBoost / LightGBM 支持自动 class weight 调整
- 或使用 Focal Loss(适用于样本极端不平衡)
# ✅ C. 评估指标选择优化
常见指标 | 是否可靠 | 原因 |
---|---|---|
Accuracy | ❌ 不可靠 | 多数类太多时,虚高 |
F1-score | ⚠️ 需关注分类 | 加权 F1 可用,但需要查看每类情况 |
AUROC | ⚠️ 不够敏感 | 会被多数类主导,容易“好看”但实际没识别正类 |
AUPRC | ✅ 更可靠 | 关注 precision 和 recall,更适合不平衡场景 |
# 💡 五、举个例子(手工构造)
预测为 1(欺诈):20 个
其中真正的是 10(TP),误报是 10(FP)
还有 90 个真正的欺诈没被识别出来(FN)
精确率 = 10 / (10+10) = 0.5
召回率 = 10 / (10+90) = 0.1
F1 = 2 * 0.5 * 0.1 / (0.5 + 0.1) ≈ 0.167
2
3
4
5
6
7
即使看起来识别了一些,指标还是很低 → 说明不平衡带来了极大损害。
# ✅ 总结
关键点 | 内容 |
---|---|
不平衡问题 | 少数类样本远少于多数类 |
常见危害 | Accuracy 虚高、召回率低、少数类被忽略 |
数据层应对 | 欠采样、过采样(SMOTE) |
模型层应对 | 加权 loss、Focal Loss、使用支持 class_weight 的模型 |
合理指标 | 关注 F1-score、AUPRC,不推荐只看 accuracy 或 AUROC |
# 🔹 第五步:ROC 曲线与 AUROC 指标详解(Receiver Operating Characteristic)
# 📌 一、什么是 ROC 曲线?
ROC 曲线是用于评估二分类模型在各种分类阈值下的性能的图表。
# 横轴(X):FPR(假正率)
👉 实际为负却被预测为正的比例。
# 纵轴(Y):TPR(真正率)= Recall(召回率)
👉 实际为正被成功识别的比例。
# 🧠 二、ROC 曲线的意义
一个二分类模型会输出概率分数,而不是直接的类别(0 或 1):
比如:模型对某样本的输出是
P(正类) = 0.78
通过改变阈值(例如 0.3、0.5、0.7...),你会得到一组不同的 TP / FP 组合点,绘制在坐标系中,形成 ROC 曲线。
# 📈 三、ROC 曲线解读
情况 | 曲线特征 | 意义 |
---|---|---|
完美模型 | ROC 曲线从 (0,0) → (0,1) → (1,1) | AUROC = 1.0 |
完全随机 | ROC 曲线是对角线 | AUROC = 0.5 |
预测能力差 | ROC 曲线低于对角线(等价于反预测) | AUROC < 0.5 |
# 📐 四、什么是 AUROC(AUC)
AUROC = Area Under ROC Curve 即:ROC 曲线下的面积
值域为 [0, 1]:
- 1.0:完美
- 0.5:随机
- <0.5:有害(预测反了)
# ✅ AUROC 的优势:
- 与具体阈值无关
- 衡量模型整体能力(对正类概率打分比负类高的比例)
# 🧪 五、具体例子演示
你有 4 个样本(2 个正类,2 个负类),模型打分如下:
样本 | 实际类别 | 模型得分(预测正的概率) |
---|---|---|
A | 1 | 0.9 |
B | 0 | 0.8 |
C | 1 | 0.6 |
D | 0 | 0.4 |
你可以比较每对“正类 vs 负类”的得分:
- A > B ✅
- A > D ✅
- C > B ❌
- C > D ✅
总共 4 对,有 3 对预测得对:
# ⚙️ 六、Python 中绘制 ROC 曲线 & 计算 AUC
from sklearn.metrics import roc_curve, roc_auc_score
import matplotlib.pyplot as plt
# 假设你有真实标签和模型输出概率
y_true = [0, 0, 1, 1]
y_score = [0.1, 0.4, 0.35, 0.8]
fpr, tpr, thresholds = roc_curve(y_true, y_score)
auc = roc_auc_score(y_true, y_score)
plt.plot(fpr, tpr, label=f"AUROC = {auc:.2f}")
plt.plot([0, 1], [0, 1], 'k--') # 随机模型对角线
plt.xlabel("False Positive Rate")
plt.ylabel("True Positive Rate")
plt.title("ROC Curve")
plt.legend()
plt.grid()
plt.show()
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
# ⚠️ 七、ROC/AUC 的局限性
在严重类别不平衡时不可靠!
- 你有 99% 的负类时,FPR 再低也不代表模型能识别正类。
这时推荐使用 PR 曲线 + AUPRC(我们将在下一步讲)
# ✅ 小结
指标 | 解释 | 优点 | 局限 |
---|---|---|---|
ROC 曲线 | TPR vs. FPR 曲线,描绘模型不同阈值表现 | 无需选定分类阈值 | 在不平衡数据下不够敏感 |
AUROC | ROC 曲线下面积(0.5~1.0) | 衡量模型总体排序能力 | 不能反映正类被识别得是否完整 |
# 🔹 第六步:PR 曲线 & AUPRC(Precision-Recall 曲线与其面积)
# 📌 一、PR 曲线是什么?
PR 曲线 = Precision vs Recall 曲线,是另一种评估二分类模型性能的方式。
它特别适合在类别不平衡场景中使用。
# - 横轴(X):Recall(召回率)
# - 纵轴(Y):Precision(精确率)
# 📈 二、PR 曲线是如何画出来的?
模型输出的是概率(如 P(是正类) = 0.81),我们可以通过改变分类阈值,得到一系列不同的 Precision 和 Recall:
- 阈值从高到低,例如从 0.95 → 0.90 → … → 0.0
- 每个阈值下你会得到新的 TP、FP、FN,从而计算 Precision 和 Recall
就这样构成了一条曲线:Recall 向右增加,Precision 会变化。
# 📐 三、什么是 AUPRC(PR 曲线下的面积)
AUPRC = Area Under Precision-Recall Curve 即:PR 曲线下面积
# 值域解释:
- 1.0:完美模型(召回率高时仍保持高精度)
- 越接近 正类比例(如 0.1、0.01)表示模型越差
👉 在极度不平衡数据中,AUPRC 比 AUROC 更真实反映模型能力!
# 🎯 四、为什么 PR 曲线在不平衡时更可靠?
因为:
- AUROC 横轴是 FPR,容易在负类多时“看起来好看”
- PR 曲线只关注正类(Recall 和 Precision 都和 TP 相关)
👉 在罕见目标识别(如欺诈、癌症)中,PR 曲线更关注是否能找到真正的“关键样本”。
# 🧪 五、例子演示(手工)
假设你有 10 个样本,2 个正类,8 个负类,模型打分如下:
样本 | 实际标签 | 模型输出分数 |
---|---|---|
A | 1 | 0.95 |
B | 0 | 0.90 |
C | 1 | 0.85 |
D | 0 | 0.80 |
... | ... | ... |
通过不同阈值,你可以计算多个 Precision / Recall 点,然后画出 PR 曲线。
如果你有 2 个正类,而你只找出其中 1 个,精度再高,Recall 也只有 0.5 → 说明模型能力不足。
# ⚙️ 六、Python 中如何画 PR 曲线 + AUPRC
from sklearn.metrics import precision_recall_curve, average_precision_score
import matplotlib.pyplot as plt
y_true = [0, 0, 1, 1]
y_scores = [0.1, 0.4, 0.35, 0.8]
precision, recall, _ = precision_recall_curve(y_true, y_scores)
ap = average_precision_score(y_true, y_scores)
plt.plot(recall, precision, label=f"AUPRC = {ap:.2f}")
plt.xlabel("Recall")
plt.ylabel("Precision")
plt.title("Precision-Recall Curve")
plt.grid()
plt.legend()
plt.show()
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
# 🔍 七、与 AUROC 对比总结
指标 | 横轴 | 纵轴 | 更关注 | 适用场景 |
---|---|---|---|---|
ROC 曲线 | 假正率 FPR | 真正率 TPR | 所有类(偏多数) | 类别均衡时 |
PR 曲线 | 召回率 | 精确率 | 正类表现 | 类别不平衡任务 ✅ |
# ✅ 八、实际建议
在模型评估时:
如果数据 类别均衡,可以主要看 Accuracy + AUROC
如果数据 类别不平衡(特别是正类稀少):
- 看 per-class 的 Recall
- 使用 PR 曲线 & AUPRC
- 看 F1-score 是否合理
# 📌 总结一览
工具/指标 | 描述 | 何时用 |
---|---|---|
ROC 曲线 | TPR vs FPR,衡量分类排序能力 | 类别均衡,模型输出为概率 |
AUROC | ROC 曲线下面积 | 越高越好,0.5=随机,1=完美 |
PR 曲线 | Precision vs Recall,关注正类 | 类别不平衡任务中最推荐 ✅ |
AUPRC | PR 曲线下面积 | 正类识别能力越强越高,AUPRC≈正类比例=差 |
# 🔍 如何判断 AUPRC 的值“好”还是“差”?
# ✅ 一、AUPRC 是什么?
AUPRC = Precision-Recall 曲线下的面积,衡量模型对正类的识别能力
- AUPRC 的值域 ∈ [0, 1]
- 值越高 → 模型在召回较高时仍能保持较高的精确率 → 越好
# ⚠️ 二、AUPRC 的“基线”不是 0.5,而是 正类比例
这是和 AUROC 最大的区别:
指标 | 最低“参考线” | 对应基准模型表现(随机猜) |
---|---|---|
AUROC | 0.5 | 随机猜(正类比负类打分高一半) |
AUPRC | 正类频率 | 随机猜每个样本为正类的概率 |
# 🧠 举个例子
# 例子 1:正类占比 50%
- 基准线 AUPRC ≈ 0.50
- 你的模型 AUPRC = 0.75 → 很不错!
# 例子 2:正类占比 10%
- 基准线 AUPRC ≈ 0.10
- 你的模型 AUPRC = 0.50 → 非常好!
- 如果只有 0.12,那就只是略优于随机模型
# ✅ 三、怎么判断 AUPRC 表现是否优秀?
# 📊 判断标准(可参考):
正类占比 | AUPRC ≥... | 表现评价 |
---|---|---|
50% | ≥ 0.8 | 很好 |
20% | ≥ 0.6 | 优秀 |
10% | ≥ 0.5 | 表现不错 |
5% | ≥ 0.3 | 明显优于随机 |
1% | ≥ 0.15 | 非常有价值 |
= 正类频率 | = baseline | 随机模型水平 🚨 |
口诀记忆:只要远高于正类比例,就值得信任
# 📐 四、如何计算正类比例作为 baseline?
你可以这样做:
y_true = [0, 0, 1, 1, 0, 0, 0, 1, 0, 0]
positive_ratio = sum(y_true) / len(y_true)
print("Baseline AUPRC:", positive_ratio)
2
3
输出:
Baseline AUPRC: 0.3
如果你的模型 AUPRC = 0.65,就说明模型性能明显优于随机。
# 🔍 五、模型对比时更有意义
- 如果你有多个模型(如 Logistic 回归 / 神经网络 / LightGBM), → 选择 AUPRC 更高的
- 可结合 F1-score / 正类 recall 分析细节
# ✅ 六、总结
问题 | 回答 |
---|---|
AUPRC 取值范围 | 0 到 1 |
baseline 是多少? | 等于正类样本在所有样本中所占比例 |
多高才算好? | 远高于 baseline(例如 5 倍、10 倍) |
AUPRC vs AUROC | AUPRC 更关注正类识别,适合不平衡分类 |
实战建议 | 看 AUPRC 是否远高于 baseline,再结合 F1 分析 |