Metriche di classificazione: accuracy, precision, recall e F1
Calcolerà tutte e quattro le metriche sulle stesse previsioni e comprenderà quale privilegiare in base al costo dei falsi positivi rispetto ai falsi negativi.
Metriche di classificazione: accuracy, precision, recall e F1 è una lezione Machine Learning Academy gratuita su CoddyKit. Questa è la lezione 1 di 4. Puoi leggere la lezione completa qui gratuitamente — poi esercitati direttamente nel browser con un editor di codice integrato e un tutor IA disponibile 24/7. Fa parte del percorso di apprendimento Machine Learning Academy, e i tuoi progressi si sincronizzano tra il web e l'app CoddyKit. Il corso Machine Learning Academy include 4 lezioni in totale.
Parti di questa lezione non sono ancora state tradotte e vengono mostrate in inglese.
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.
Domande Frequenti
La lezione «Metriche di classificazione: accuracy, precision, recall e F1» è gratuita?
Sì — il testo completo di «Metriche di classificazione: accuracy, precision, recall e F1» è gratuito qui sul web. Per esercitarvi in modo interattivo (un editor di codice integrato e un tutor IA 24/7) e sbloccare il resto del corso Machine Learning Academy, passa a CoddyKit PRO. Il corso Machine Learning Academy include 4 lezioni in totale.
Cosa imparerò in «Metriche di classificazione: accuracy, precision, recall e F1»?
Calcolerà tutte e quattro le metriche sulle stesse previsioni e comprenderà quale privilegiare in base al costo dei falsi positivi rispetto ai falsi negativi. Eserciti Machine Learning Academy con codice pratico che esegui direttamente nel browser, e un tutor IA 24/7 risponde alle tue domande mentre lavori sulla lezione.
Ho bisogno di esperienza per iniziare Machine Learning Academy?
Non è richiesta alcuna esperienza precedente. Machine Learning Academy su CoddyKit è strutturato per principianti e studenti avanzati, quindi puoi iniziare da qui o dall'inizio e procedere al tuo ritmo. Questa è la lezione 1 di 4.
Quanto tempo richiede la lezione «Metriche di classificazione: accuracy, precision, recall e F1»?
La maggior parte delle lezioni CoddyKit richiede circa 5–10 minuti. Ogni lezione è breve e interattiva, quindi fai progressi costanti e riprendi esattamente da dove hai lasciato su web e app.
Posso scrivere ed eseguire codice in questa lezione Machine Learning Academy?
Sì. Ogni lezione Machine Learning Academy include un editor di codice integrato, quindi scrivi ed esegui codice reale direttamente nel tuo browser e ricevi feedback istantaneo dall'IA — nessuna configurazione locale necessaria.
Tutte le lezioni di questo corso
- Metriche di classificazione: accuracy, precision, recall e F1
- Curve ROC e AUC-ROC
- Metriche di regressione: MAE, MSE, RMSE e R-squared
- Scegliere la metrica giusta per il problema aziendale