📘 第5课:效果如何?使用重要指标评估你的模型

"不要用模型答对了多少来衡量它……要用它答对的东西有多重要来衡量它。"


⏱️ 本课预计时长: 75-90分钟


🧭 为什么这节课如此重要?

因为这里是你停止信任并开始验证的地方。

你训练了一个模型。
它做了预测。
但这并不意味着它很好!

许多初学者对"98%的准确率"感到兴奋……然后发现他们的模型在最重要的情况下失败了

在本课中,你将学习:

  • 为什么准确率不是一切(特别是在数据不平衡的情况下!)。
  • 什么是混淆矩阵以及如何像专业人士一样阅读它。
  • 精确率、召回率和F1分数的含义……以及何时使用它们。
  • 如何解释概率,而不仅仅是标签。
  • 如何避免被表面指标愚弄

⚠️ 友好提醒: 这节课会让你质疑你认为知道的所有关于"好模型"的知识。但这是好事。谦逊是改进之母。


🎯 本课目标

完成后,你将能够:

✅ 计算和解释模型的准确率。
✅ 构建和理解混淆矩阵。
✅ 计算和解释精确率、召回率和F1分数。
✅ 知道何时根据问题使用每种指标。
✅ 评估不仅仅是预测,还有概率。
✅ 检测你的模型是"愚蠢的"还是真正智能的。
✅ 舒适地基于指标而非直觉做决策。


🛠️ 你将使用的工具

  • Scikit-learnaccuracy_scoreconfusion_matrixclassification_reportprecision_recall_curve
  • Matplotlib / Seaborn → 可视化指标。
  • Pandas → 操作结果。

💡 确保你有从第4课训练好的模型和预测结果(y_testy_pred)。如果没有,这里是快速跟上的代码:

import pandas as pd
from sklearn.model_selection import train_test_split
from sklearn.feature_extraction.text import CountVectorizer
from sklearn.naive_bayes import MultinomialNB

# 加载和准备数据
url = "https://raw.githubusercontent.com/justmarkham/DAT8/master/data/sms.tsv  "
data = pd.read_csv(url, sep='\t', names=['label', 'message'])
data['label_encoded'] = data['label'].map({'ham': 0, 'spam': 1})

X = data['message']
y = data['label_encoded']
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42, stratify=y)

vectorizer = CountVectorizer()
X_train_vec = vectorizer.fit_transform(X_train)
X_test_vec = vectorizer.transform(X_test)

# 训练模型
model = MultinomialNB()
model.fit(X_train_vec, y_train)

# 预测
y_pred = model.predict(X_test_vec)

📊 第1部分:准确率的错觉——真的是98%吗?

让我们从最流行……也是最危险的指标开始。


🔹 步骤1:计算准确率

from sklearn.metrics import accuracy_score

acc = accuracy_score(y_test, y_pred)
print(f"准确率: {acc:.4f} → {acc*100:.2f}%")

📌 典型输出:

准确率: 0.9821 → 98.21%

→ 哇!98%正确。这是否意味着模型很优秀?

不! 这就是原因。


🔍 不平衡数据的问题

记住:在我们的数据集中,只有13.4%是垃圾邮件。86.6%是正常邮件。

想象一个愚蠢的模型,它总是预测"ham"。
它的准确率会是多少?

准确率 = (真实正常邮件) / (总数) = 955 / 1115 ≈ 85.65%

→ 一个从不检测垃圾邮件的模型会有85.65%的准确率!

你的模型有98.21% → 比愚蠢的模型好……但在真正重要的事情上好多少:检测垃圾邮件?

📌 结论: 当存在不平衡时,准确率会误导。你需要更聪明的指标。


🧩 第2部分:混淆矩阵——你的错误显微镜

这里你可以看到模型究竟在哪些方面成功和失败


🔹 步骤2:构建混淆矩阵

from sklearn.metrics import confusion_matrix
import seaborn as sns
import matplotlib.pyplot as plt

cm = confusion_matrix(y_test, y_pred)

# 可视化
plt.figure(figsize=(8, 6))
sns.heatmap(cm, annot=True, fmt='d', cmap='Blues', 
            xticklabels=['正常邮件(预测)', '垃圾邮件(预测)'], 
            yticklabels=['正常邮件(真实)', '垃圾邮件(真实)'])
plt.title("混淆矩阵 - 垃圾邮件分类器", fontsize=16)
plt.ylabel("真实标签", fontsize=12)
plt.xlabel("预测标签", fontsize=12)
plt.show()

📌 典型输出(近似值):

          预测
          正常邮件  垃圾邮件
真实正常邮件  950    5
真实垃圾邮件   15  145

🔍 如何阅读这个矩阵?

  • 真负例 (TN): 950
    → 模型说是正常邮件的真实正常邮件。✅ 完美!

  • 假正例 (FP): 5
    → 模型说是垃圾邮件的真实正常邮件。❌ 严重错误!(把重要邮件标记为垃圾邮件)。

  • 假负例 (FN): 15
    → 模型说是正常邮件的真实垃圾邮件。❌ 严重错误!(让垃圾邮件通过)。

  • 真正例 (TP): 145
    → 模型说是垃圾邮件的真实垃圾邮件。✅ 完美!

📌 这是黄金! 现在你知道模型在哪里失败了。这不是抽象的数字……这些是你能够改进的具体错误。


🎯 第3部分:精确率、召回率和F1分数——重要的3个指标

现在,让我们用专业指标来量化这些错误。


🔹 步骤3:计算分类报告

from sklearn.metrics import classification_report

report = classification_report(y_test, y_pred, 
                               target_names=['正常邮件', '垃圾邮件'], 
                               output_dict=False)
print(report)

📌 典型输出:

              precision    recall  f1-score   support

         正常邮件    0.98      0.99      0.99       955
        垃圾邮件    0.97      0.91      0.94       160

    accuracy                           0.98      1115
   macro avg       0.98      0.95      0.96      1115
weighted avg       0.98      0.98      0.98      1115

🔍 这些指标是什么意思?

1. 精确率

"在我所说的垃圾邮件中,有多少真的是垃圾邮件?"

精确率 (垃圾邮件) = TP / (TP + FP) = 145 / (145 + 5) = 145/150 ≈ 0.97

垃圾邮件精确率97%:当模型说"垃圾邮件"时,有97%的时间是正确的。优秀!

📌 什么时候精确率重要?
假正例的代价很高时。
例如:把重要邮件标记为垃圾邮件 → 用户可能丢失关键信息。


2. 召回率 (敏感性, 真正例率)

"在所有存在的垃圾邮件中,我检测到了多少?"

召回率 (垃圾邮件) = TP / (TP + FN) = 145 / (145 + 15) = 145/160 ≈ 0.91

垃圾邮件召回率91%:检测到了91%的所有垃圾邮件。非常好!

📌 什么时候召回率重要?
假负例的代价很高时。
例如:让欺诈垃圾邮件通过 → 用户可能点击并损失金钱。


3. F1分数

"精确率和召回率的调和平均值。当你想要平衡时理想。"

F1 = 2 * (精确率 * 召回率) / (精确率 + 召回率)
   = 2 * (0.97 * 0.91) / (0.97 + 0.91) ≈ 0.94

F1分数94%:在不打扰用户(精确率)和保护用户(召回率)之间取得良好平衡。

📌 什么时候使用F1?
当你不知道什么更重要时,或者当你想要一个总结不平衡类别表现的单一指标时。


📈 第4部分:超越标签——评估概率

你的模型不仅预测"垃圾邮件"或"正常邮件"。它还给你概率

这很强大。因为有时,你不想做二元决策……你想知道模型有多确定


🔹 步骤4:获取概率

# 获取每类的概率
y_proba = model.predict_proba(X_test_vec)

# 对于垃圾邮件(类别1),是第二列
y_proba_spam = y_proba[:, 1]

# 查看前10个概率
for i in range(10):
    print(f"消息 {i+1}: 垃圾邮件概率 = {y_proba_spam[i]:.4f} → 预测: {'垃圾邮件' if y_pred[i] == 1 else '正常邮件'}")

📌 典型输出:

消息 1: 垃圾邮件概率 = 0.0002 → 预测: 正常邮件
消息 2: 垃圾邮件概率 = 0.9998 → 预测: 垃圾邮件
消息 3: 垃圾邮件概率 = 0.0015 → 预测: 正常邮件
...

→ 太棒了!模型不仅说"垃圾邮件",还告诉你"我有99.98%的把握"。


🔹 步骤5:精确率-召回率曲线(可选,但有启发性)

如果你改变决策阈值会发生什么?

默认情况下,如果概率 > 0.5 → 垃圾邮件。
但如果你使用0.7呢?或者0.3?

from sklearn.metrics import precision_recall_curve
import matplotlib.pyplot as plt

precision, recall, thresholds = precision_recall_curve(y_test, y_proba_spam)

plt.figure(figsize=(10, 6))
plt.plot(recall, precision, marker='.', label='朴素贝叶斯')
plt.xlabel('召回率')
plt.ylabel('精确率')
plt.title('精确率-召回率曲线')
plt.legend()
plt.grid(True)
plt.show()

📌 你看到了什么?
一条曲线,显示不同阈值下精确率和召回率之间的权衡。
理想的用于选择适合你需求的阈值(更多精确率或更多召回率)。


❌ 本课常见错误(避免它们!)

  1. 只信任准确率 → 你会错过关键错误。
  2. 忽略混淆矩阵 → 你看不到模型在哪里失败。
  3. 不理解精确率和召回率的区别 → 你会做出错误决策。
  4. 忘记指标取决于问题 → 在医学中,召回率至关重要;在广告中,精确率重要。
  5. 不使用概率 → 你会失去关于模型置信度的宝贵信息。

✅ 本课检查清单——你现在应该知道如何做:

☐ 计算和解释准确率。
☐ 构建和阅读混淆矩阵。
☐ 计算和解释精确率、召回率和F1分数。
☐ 知道何时根据问题优先考虑精确率vs召回率。
☐ 获取和分析预测概率。
☐ 理解"好"模型取决于上下文,而不仅仅是一个数字。
☐ 舒适地用专业严谨性评估模型。


🎯 要记住的话:

"不要用模型答对了多少来衡量它……要用它答对的东西有多重要来衡量它。"


Course Info

Course: AI-course0

Language: ZH

Lesson: 5 evaluate model