Machine Learning Academy · 课时

分类指标:准确率、精确率、召回率与 F1

您将使用同一组预测结果计算全部四项指标,并根据假正例与假负例的代价,理解应优先关注哪项指标

第 1 / 4 课13 个步骤

分类指标:准确率、精确率、召回率与 F1 是 CoddyKit 上的免费 Machine Learning Academy 课时。 这是第 1 节课,共 4 节。 你可以在下方免费阅读本课时的完整内容 — 然后在浏览器中使用内置代码编辑器和全天候 AI 导师进行实践。 这是 Machine Learning Academy 学习路径的一部分,你的进度在网页和 CoddyKit 应用中同步。 Machine Learning Academy 课程共包含 4 节课。

本课时的部分内容尚未翻译,以英文显示。

Why Accuracy Is Often Not Enough

Accuracy — the fraction of correct predictions — is the most intuitive metric, but it is misleading when classes are imbalanced. Consider a medical test for a disease that affects 1% of patients. A model that always predicts 'healthy' achieves 99% accuracy while being completely useless — it misses every actual disease case. In fraud detection, cancer screening, or rare event prediction, accuracy hides the model's failure to detect the rare but critical positive class. This is why we need metrics that separately measure performance on each class: precision, recall, and F1-score.

import numpy as np

# 1000 patients: 990 healthy, 10 sick
y_true = [0]*990 + [1]*10
y_pred_dummy = [0]*1000  # Always predict healthy

correct = sum(p == t for p, t in zip(y_pred_dummy, y_true))
accuracy = correct / len(y_true)
print(f'Dummy accuracy: {accuracy:.1%}')  # 99.0% -- misleadingly high!
print('But 0 sick patients correctly identified!')
print('This is why we need precision and recall.')

The Confusion Matrix: Ground Truth

The confusion matrix is the foundation of all classification metrics. For binary classification, it is a 2x2 table: True Positives (TP) — correctly predicted positive; True Negatives (TN) — correctly predicted negative; False Positives (FP) — predicted positive but actually negative (Type I error); False Negatives (FN) — predicted negative but actually positive (Type II error). Every classification metric is derived from some combination of these four numbers. Inspecting the raw confusion matrix reveals which type of error the model makes most.

from sklearn.metrics import confusion_matrix
import numpy as np

y_true = [1, 0, 1, 1, 0, 0, 1, 0, 0, 1]
y_pred = [1, 0, 1, 0, 0, 1, 1, 0, 0, 0]

cm = confusion_matrix(y_true, y_pred)
print('Confusion Matrix:')
print(cm)
# [[TN, FP],
#  [FN, TP]]
TN, FP, FN, TP = cm.ravel()
print(f'TP={TP}, TN={TN}, FP={FP}, FN={FN}')

Accuracy: Simple but Limited

Accuracy = (TP + TN) / (TP + TN + FP + FN). It answers: of all predictions, what fraction were correct? Accuracy is a fair metric only when classes are roughly balanced and the costs of false positives and false negatives are similar. For example, handwritten digit recognition with ~10% of each digit class is balanced, making accuracy a reasonable measure. Use accuracy when: classes are balanced and all errors have equal cost. Avoid it when: classes are skewed (one class dominates) or false negatives cost more than false positives (or vice versa).

from sklearn.metrics import accuracy_score, confusion_matrix
import numpy as np

y_true = [1, 0, 1, 1, 0, 0, 1, 0, 0, 1]
y_pred = [1, 0, 1, 0, 0, 1, 1, 0, 0, 0]

acc = accuracy_score(y_true, y_pred)
print(f'Accuracy = {acc:.2f}')  # (TP+TN) / total

# Manual calculation
TN, FP, FN, TP = confusion_matrix(y_true, y_pred).ravel()
acc_manual = (TP + TN) / (TP + TN + FP + FN)
print(f'Manual: ({TP}+{TN}) / ({TP}+{TN}+{FP}+{FN}) = {acc_manual:.2f}')

Precision: Quality of Positive Predictions

Precision = TP / (TP + FP). It answers: of all the samples we predicted as positive, what fraction actually are positive? Precision is the metric to optimise when false positives are costly. In spam detection: a high-precision spam filter rarely marks legitimate email as spam. In drug testing: high precision means we rarely approve a drug that does not work. Low precision means many of our positive predictions are wrong — we are flooding users with false alarms. Precision tells you nothing about the false negatives — a model that only predicts one obvious case as positive has precision 1.0 but misses everything else.

from sklearn.metrics import precision_score, confusion_matrix
import numpy as np

y_true = [1, 0, 1, 1, 0, 0, 1, 0, 0, 1]
y_pred = [1, 0, 1, 0, 0, 1, 1, 0, 0, 0]

prec = precision_score(y_true, y_pred)
print(f'Precision = {prec:.2f}')

# Manual calculation
TN, FP, FN, TP = confusion_matrix(y_true, y_pred).ravel()
print(f'Manual: TP/(TP+FP) = {TP}/({TP}+{FP}) = {TP/(TP+FP):.2f}')
print('Of all PREDICTED positives, this fraction are truly positive.')

Recall: Coverage of Actual Positives

Recall = TP / (TP + FN) (also called Sensitivity or True Positive Rate). It answers: of all samples that actually are positive, what fraction did we find? Recall is the metric to optimise when false negatives are costly. In cancer screening: high recall means we identify most patients who actually have cancer. In fraud detection: high recall means we catch most fraudulent transactions. Low recall means we are missing too many actual positives — dangerous in medical or security contexts. Recall and precision are in tension: increasing one typically decreases the other.

from sklearn.metrics import recall_score, confusion_matrix
import numpy as np

y_true = [1, 0, 1, 1, 0, 0, 1, 0, 0, 1]
y_pred = [1, 0, 1, 0, 0, 1, 1, 0, 0, 0]

rec = recall_score(y_true, y_pred)
print(f'Recall = {rec:.2f}')

# Manual calculation
TN, FP, FN, TP = confusion_matrix(y_true, y_pred).ravel()
print(f'Manual: TP/(TP+FN) = {TP}/({TP}+{FN}) = {TP/(TP+FN):.2f}')
print('Of all ACTUAL positives, this fraction were correctly identified.')

The Precision-Recall Trade-Off

Precision and recall are inversely related when you adjust the classification threshold. As you lower the threshold (predict positive more aggressively), recall increases (you catch more actual positives) but precision decreases (more false positives get through). Raising the threshold has the opposite effect. There is no single threshold that simultaneously maximises both. Which metric to prioritise depends on the business problem: in email filtering, prioritise precision (do not annoy users with false spam alerts); in disease screening, prioritise recall (do not miss sick patients).

from sklearn.metrics import precision_score, recall_score
from sklearn.linear_model import LogisticRegression
from sklearn.datasets import load_breast_cancer
from sklearn.model_selection import train_test_split
import numpy as np

X, y = load_breast_cancer(return_X_y=True)
X_tr, X_te, y_tr, y_te = train_test_split(X, y, random_state=42)

clf = LogisticRegression(max_iter=10000)
clf.fit(X_tr, y_tr)
proba = clf.predict_proba(X_te)[:, 1]

for thresh in [0.3, 0.5, 0.7, 0.9]:
    y_pred = (proba >= thresh).astype(int)
    prec = precision_score(y_te, y_pred, zero_division=0)
    rec  = recall_score(y_te, y_pred)
    print(f'threshold={thresh}: precision={prec:.3f}, recall={rec:.3f}')

F1-Score: Harmonic Mean of Precision and Recall

F1-score = 2 * (Precision * Recall) / (Precision + Recall). The F1-score is the harmonic mean of precision and recall. Unlike the arithmetic mean, the harmonic mean punishes extreme values: a model with precision=1.0 and recall=0.0 gets F1=0, not 0.5. This makes F1 a fair aggregate metric that requires both precision and recall to be reasonably high. F1 is the standard metric for imbalanced text classification (NLP benchmarks always report it), fraud detection, and any problem where class imbalance makes accuracy misleading.

from sklearn.metrics import f1_score, precision_score, recall_score
import numpy as np

y_true = [1, 0, 1, 1, 0, 0, 1, 0, 0, 1]
y_pred = [1, 0, 1, 0, 0, 1, 1, 0, 0, 0]

prec = precision_score(y_true, y_pred)
rec  = recall_score(y_true, y_pred)
f1   = f1_score(y_true, y_pred)

print(f'Precision = {prec:.3f}')
print(f'Recall    = {rec:.3f}')
print(f'F1-Score  = {f1:.3f}')
print(f'Manual F1 = 2 * ({prec:.3f} * {rec:.3f}) / ({prec:.3f} + {rec:.3f}) = {2*prec*rec/(prec+rec):.3f}')

Fbeta-Score: Weighted Precision-Recall Balance

The Fbeta score generalises F1 by introducing a parameter beta that controls how much to weight recall relative to precision: F_beta = (1 + beta^2) * Precision * Recall / (beta^2 * Precision + Recall). When beta=1, this is the standard F1 score. When beta=2 (F2), recall is weighted twice as much as precision — useful when missing positives is twice as costly as false alarms. When beta=0.5 (F0.5), precision is weighted more — useful in recommendation systems where accuracy of suggestions matters more than coverage.

from sklearn.metrics import fbeta_score
import numpy as np

y_true = [1, 0, 1, 1, 0, 0, 1, 0, 0, 1]
y_pred = [1, 0, 1, 0, 0, 1, 1, 0, 0, 0]

for beta in [0.5, 1.0, 2.0]:
    score = fbeta_score(y_true, y_pred, beta=beta)
    print(f'F{beta:.1f} = {score:.3f}')

print()
print('beta=0.5: precision weighted 2x -> use when false alarms costly')
print('beta=1.0: balanced precision/recall -> standard F1')
print('beta=2.0: recall weighted 2x -> use when missing positives costly')

Multi-Class Averaging: Macro, Micro, and Weighted

For multi-class classification, you must aggregate per-class precision/recall/F1 into a single number. Macro average: compute metric for each class independently, then average — treats all classes equally regardless of size. Weighted average: same but weights by class support — gives larger classes more influence. Micro average: aggregate TP/FP/FN across all classes first, then compute — equivalent to accuracy for precision, recall, and F1 when there are no samples with multiple labels. Use macro for imbalanced datasets where small minority classes are important.

from sklearn.metrics import f1_score
import numpy as np

# Multi-class predictions
y_true = [0, 0, 1, 1, 2, 2, 2]
y_pred = [0, 1, 1, 1, 2, 0, 2]

print('Macro F1:    ', f1_score(y_true, y_pred, average='macro').round(3))
print('Micro F1:    ', f1_score(y_true, y_pred, average='micro').round(3))
print('Weighted F1: ', f1_score(y_true, y_pred, average='weighted').round(3))
print('Per-class F1:', f1_score(y_true, y_pred, average=None).round(3))
print()
print('Macro treats all classes equally (even rare ones)')
print('Weighted rewards correct prediction of common classes')

classification_report: All Metrics in One

classification_report() generates a formatted table showing precision, recall, F1-score, and support (number of true instances) for each class, plus macro/weighted averages. This is the standard output to include in any ML evaluation report. The 'support' column is especially important: a class with support=5 will have noisy precision/recall estimates and should be interpreted cautiously. Always check support values alongside F1 scores to assess metric reliability.

from sklearn.metrics import classification_report
from sklearn.ensemble import RandomForestClassifier
from sklearn.datasets import load_iris
from sklearn.model_selection import train_test_split

X, y = load_iris(return_X_y=True)
X_tr, X_te, y_tr, y_te = train_test_split(X, y, test_size=0.3, random_state=42)

clf = RandomForestClassifier(random_state=42)
clf.fit(X_tr, y_tr)
y_pred = clf.predict(X_te)

print(classification_report(
    y_te, y_pred,
    target_names=load_iris().target_names
))

Balanced Accuracy for Imbalanced Classes

Balanced accuracy is the arithmetic mean of sensitivity (recall for each class). For binary classification: balanced_accuracy = (TPR + TNR) / 2 where TNR (True Negative Rate) = TN / (TN+FP). Unlike standard accuracy, balanced accuracy gives equal weight to each class regardless of how many samples it has. A model that always predicts the majority class gets balanced accuracy of 0.5 — correctly identifying it as no better than random. Use balanced accuracy when classes are imbalanced and you want a single metric that reflects performance on all classes equally, without the complexity of computing per-class metrics.

from sklearn.metrics import balanced_accuracy_score, accuracy_score
import numpy as np

# Imbalanced: 990 class 0, 10 class 1
y_true = np.array([0]*990 + [1]*10)
y_dummy = np.zeros(1000, dtype=int)  # Always predict class 0

acc_standard = accuracy_score(y_true, y_dummy)
acc_balanced = balanced_accuracy_score(y_true, y_dummy)

print(f'Standard accuracy: {acc_standard:.3f}')  # 99% -- misleading
print(f'Balanced accuracy: {acc_balanced:.3f}')  # 0.5 -- correctly shows no skill
print()
print('Balanced accuracy correctly penalises ignoring the minority class')

Quick Check

Test your understanding of Machine Learning with Python concepts from this lesson.

Lesson Recap

In this lesson you learned: accuracy is misleading for imbalanced classes — use the confusion matrix as ground truth, precision measures quality of positive predictions (minimise false positives) and recall measures coverage of actual positives (minimise false negatives), and F1-score harmonically combines both into a balanced metric. Next up we explore ROC curves and AUC-ROC for threshold-independent model evaluation.

免费开始

用 AI 导师学习 Python — 免费

在浏览器中编写并运行真实代码,获得全天候 AI 导师的即时帮助,并在网页或应用中继续学习。

课程
30
课程
120

常见问题解答

「分类指标:准确率、精确率、召回率与 F1」课时是免费的吗?

是的 — 「分类指标:准确率、精确率、召回率与 F1」的完整文本可在网页上免费阅读。要进行交互式练习(内置代码编辑器和全天候 AI 导师)并解锁 Machine Learning Academy 课程的其余内容,请升级到 CoddyKit PRO。 Machine Learning Academy 课程共包含 4 节课。

「分类指标:准确率、精确率、召回率与 F1」这节课中我会学到什么?

您将使用同一组预测结果计算全部四项指标,并根据假正例与假负例的代价,理解应优先关注哪项指标 你通过在浏览器中直接运行的动手代码来练习 Machine Learning Academy,全天候 AI 导师会在你学习这节课的过程中回答你的问题。

学习 Machine Learning Academy 需要有经验吗?

无需任何先前经验。CoddyKit 上的 Machine Learning Academy 课程适合初学者到高级学习者,你可以从这里开始或从头开始,按照自己的节奏学习。 这是第 1 节课,共 4 节。

「分类指标:准确率、精确率、召回率与 F1」课时需要多长时间?

大多数 CoddyKit 课程大约需要 5–10 分钟。每节课都很精短且互动,所以你能稳步进步,并在网页和应用中从离开的地方继续。

我能在这节 Machine Learning Academy 课中编写并运行代码吗?

能。每节 Machine Learning Academy 课都包含内置代码编辑器,你可以在浏览器中直接编写并运行真实代码,并获得即时 AI 反馈 — 无需本地设置。

此课程中的所有课时

  1. 分类指标:准确率、精确率、召回率与 F1
  2. ROC 曲线与 AUC-ROC
  3. 回归指标:MAE、MSE、RMSE 与 R 平方
  4. 为业务问题选择合适的指标
← 返回 Machine Learning Academy