W3docs

Machine Learning: Capire la Matrice di Confusione

Scopri cos'è una matrice di confusione, come costruirla in Python con scikit-learn, visualizzarla con seaborn e ricavare precisione, recall e F1-score.

Una matrice di confusione è una tabella che riassume i risultati delle previsioni di un modello di classificazione, confrontando le etichette reali con quelle previste. È il punto di partenza per calcolare precisione, recall, F1-score e la maggior parte delle altre metriche di classificazione.

Questo capitolo tratta:

  • Il significato delle quattro celle (TP, FP, TN, FN) e l'importanza di ciascuna
  • Come calcolare le metriche comuni a partire da quelle celle
  • Come costruire e visualizzare una matrice di confusione in Python con scikit-learn e seaborn
  • Matrici di confusione multiclasse
  • Errori comuni, in particolare su dataset sbilanciati

Che cos'è una Matrice di Confusione?

Per un classificatore binario (due classi possibili: positiva e negativa), la matrice di confusione è una tabella 2×2:

Predetto PositivoPredetto Negativo
Effettivo PositivoTrue Positive (TP)False Negative (FN)
Effettivo NegativoFalse Positive (FP)True Negative (TN)

Ogni cella conta un tipo specifico di esito:

TermineAbbreviazioneSignificato
True PositiveTPIl modello prevede positivo; la realtà è positiva ✓
True NegativeTNIl modello prevede negativo; la realtà è negativa ✓
False PositiveFPIl modello prevede positivo; la realtà è negativa ✗ (Errore di Tipo I)
False NegativeFNIl modello prevede negativo; la realtà è positiva ✗ (Errore di Tipo II)

Un aiuto mnemonico: la prima parola (True / False) indica se la previsione era corretta; la seconda parola (Positive / Negative) indica cosa ha previsto il modello.

Metriche Derivate dalla Matrice

I quattro conteggi alimentano ogni metrica di classificazione standard:

MetricaFormulaCosa misura
Accuracy(TP + TN) / (TP + TN + FP + FN)Frazione complessiva di previsioni corrette
PrecisionTP / (TP + FP)Tra tutte le previsioni positive, quante erano corrette
Recall (Sensitivity)TP / (TP + FN)Tra tutti i positivi reali, quanti sono stati trovati
SpecificityTN / (TN + FP)Tra tutti i negativi reali, quanti sono stati correttamente esclusi
F1-Score2 × Precision × Recall / (Precision + Recall)Media armonica di precisione e recall

Quando privilegiare la precisione rispetto al recall

  • Privilegia il recall quando perdere un caso positivo è costoso — screening medico, rilevamento di frodi, filtri antispam che devono intercettare ogni messaggio spam.
  • Privilegia la precisione quando i falsi allarmi sono costosi — raccomandazioni chirurgiche, segnalazione di documenti legali, sistemi di notifiche push.
  • L'F1-score bilancia entrambi ed è la metrica predefinita quando il dataset è sbilanciato.

Esempio Numerico Pratico

Supponiamo che un modello esamini 100 pazienti per una malattia:

  • TP = 50 (pazienti malati correttamente identificati)
  • FP = 5 (pazienti sani erroneamente segnalati come malati)
  • FN = 10 (pazienti malati non rilevati)
  • TN = 35 (pazienti sani correttamente classificati)

Calcoli passo per passo:

Accuracy  = (50 + 35) / 100 = 0.85  (85 %)
Precision = 50 / (50 + 5)  ≈ 0.909 (90.9 %)
Recall    = 50 / (50 + 10) ≈ 0.833 (83.3 %)
F1-Score  = 2 × 0.909 × 0.833 / (0.909 + 0.833) ≈ 0.869 (86.9 %)

Si noti che l'accuracy (85 %) appare accettabile, ma il recall è solo l'83 % — ovvero 10 pazienti malati su 60 sono stati mancati. In un contesto medico quella differenza è molto più significativa del dato sull'accuracy.

Costruire una Matrice di Confusione in Python

Utilizzo di scikit-learn

sklearn.metrics fornisce confusion_matrix() e un report testuale già pronto tramite classification_report().

from sklearn.metrics import confusion_matrix, classification_report

# Ground-truth labels and model predictions
y_true = [1, 1, 0, 0, 1, 0, 1, 0, 1, 0]
y_pred = [1, 0, 0, 1, 1, 0, 1, 0, 1, 1]

cm = confusion_matrix(y_true, y_pred)
print("Confusion Matrix:")
print(cm)
print()
print(classification_report(y_true, y_pred, target_names=["Negative", "Positive"]))

confusion_matrix() restituisce un array NumPy. Per impostazione predefinita, le righe rappresentano le classi reali e le colonne le classi previste (corrispondente alla disposizione della tabella mostrata sopra). La struttura dell'array è:

[[TN  FP]
 [FN  TP]]

Calcolo manuale delle metriche

Puoi estrarre le quattro celle e calcolare le metriche manualmente per verificare:

from sklearn.metrics import confusion_matrix

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

tn, fp, fn, tp = confusion_matrix(y_true, y_pred).ravel()

accuracy  = (tp + tn) / (tp + tn + fp + fn)
precision = tp / (tp + fp)
recall    = tp / (tp + fn)
f1        = 2 * precision * recall / (precision + recall)

print(f"TP={tp}, FP={fp}, FN={fn}, TN={tn}")

print(f"Accuracy : {accuracy:.3f}")
print(f"Precision: {precision:.3f}")
print(f"Recall   : {recall:.3f}")
print(f"F1-Score : {f1:.3f}")

Output atteso:

TP=4, FP=2, FN=1, TN=3
Accuracy : 0.700
Precision: 0.667
Recall   : 0.800
F1-Score : 0.727

Visualizzazione con seaborn

Una heatmap rende la matrice di confusione più leggibile, specialmente per i problemi multiclasse:

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

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

cm = confusion_matrix(y_true, y_pred)

sns.heatmap(
    cm,
    annot=True,
    fmt="d",
    cmap="Blues",
    xticklabels=["Negative", "Positive"],
    yticklabels=["Negative", "Positive"],
)
plt.xlabel("Predicted label")
plt.ylabel("True label")
plt.title("Confusion Matrix")
plt.tight_layout()
plt.savefig("confusion_matrix.png", dpi=150)
plt.show()

annot=True stampa il conteggio all'interno di ogni cella; fmt="d" li formatta come interi.

Matrici di Confusione Multiclasse

Quando le classi sono più di due, la matrice di confusione si espande in una griglia N×N. Ogni riga rappresenta ancora le classi reali; ogni colonna rappresenta le classi previste. Le celle sulla diagonale sono previsioni corrette; le celle fuori dalla diagonale sono errori.

from sklearn.metrics import confusion_matrix, ConfusionMatrixDisplay
import matplotlib.pyplot as plt

# Three classes: cat, dog, rabbit
y_true = ["cat", "dog", "rabbit", "cat", "dog", "rabbit",
          "cat", "dog", "cat", "rabbit"]
y_pred = ["cat", "dog", "rabbit", "dog", "dog", "cat",
          "cat", "rabbit", "cat", "rabbit"]

labels = ["cat", "dog", "rabbit"]
cm = confusion_matrix(y_true, y_pred, labels=labels)
print(cm)

disp = ConfusionMatrixDisplay(confusion_matrix=cm, display_labels=labels)
disp.plot(cmap="Blues")
plt.title("Multi-Class Confusion Matrix")
plt.tight_layout()
plt.savefig("cm_multiclass.png", dpi=150)
plt.show()

ConfusionMatrixDisplay (aggiunto in scikit-learn 0.24) è una comoda alternativa in una sola riga alla heatmap di seaborn e non richiede la dipendenza da seaborn.

Per i problemi multiclasse, precisione e recall vengono calcolati per classe e poi mediati. classification_report() offre tre strategie di media:

  • macro — media non ponderata tra le classi (tratta tutte le classi allo stesso modo).
  • weighted — media ponderata per il supporto (numero di istanze reali per classe).
  • micro — aggrega TP/FP/FN tra tutte le classi prima di dividere (fornisce l'accuracy complessiva per dataset bilanciati).

Errori Comuni

L'accuracy è fuorviante su dataset sbilanciati

Consideriamo un dataset in cui il 95 % dei campioni è negativo. Un modello che prevede sempre negativo raggiunge il 95 % di accuracy ma ha recall zero — non individua mai un caso positivo. La matrice di confusione lo rivela immediatamente: l'intera prima riga (Effettivo Positivo) sarà tutta FN.

Abbina sempre l'accuracy a precisione, recall o F1-score su dati sbilanciati. Consulta il capitolo Train/Test Split per come creare una suddivisione rappresentativa e il capitolo AUC-ROC Curve per una metrica di valutazione indipendente dalla soglia.

Scelta della strategia di media errata

Usare la media macro quando le classi sono molto sbilanciate gonfia il punteggio delle classi rare. Usa weighted per un quadro realistico della qualità complessiva del modello sull'intero dataset.

Dimenticare la normalizzazione

I conteggi grezzi dipendono dalla dimensione del dataset. Quando si confrontano modelli addestrati su dataset di dimensioni diverse, normalizza la matrice dividendo ogni riga per la sua somma (passa normalize='true' a confusion_matrix()):

cm_normalized = confusion_matrix(y_true, y_pred, normalize="true")
print(cm_normalized.round(2))

Ogni riga ora somma a 1.0, mostrando la frazione di ogni classe reale prevista correttamente.

Matrice di Confusione vs. Altri Strumenti di Valutazione

StrumentoIdeale per
Matrice di confusioneComprendere i tipi specifici di errori che un modello commette
AUC-ROC CurveConfrontare classificatori su tutte le soglie di decisione
Cross-ValidationStimare quanto bene la matrice si generalizza su dati non visti
Grid SearchOttimizzare gli iperparametri usando una metrica scelta (es. F1-score)

Punti Chiave

  • Una matrice di confusione suddivide le previsioni in TP, FP, TN e FN — quattro conteggi che rivelano quali errori commette un modello, non solo quanti.
  • L'accuracy da sola è insufficiente; controlla sempre precisione, recall e F1-score, specialmente su dati sbilanciati.
  • Usa sklearn.metrics.confusion_matrix() per il calcolo e seaborn o ConfusionMatrixDisplay per la visualizzazione.
  • Le matrici multiclasse seguono la stessa convenzione riga = reale, colonna = previsto e si scalano a N×N.
  • Adatta la strategia di media (macro, weighted, micro) alla distribuzione delle classi del tuo dataset.
Was this page helpful?