4.4 Matricea de confuzie și curbele ROC
Un singur număr (acuratețea) ascunde ce greșește modelul. Matricea de confuzie și curba ROC arată exact unde și cum greșește — și cum poți repara.
Teorie
Construcția matricei de confuzie
Tabel cu clasele reale pe rânduri și cele prezise pe coloane; celula (i, j) numără exemplele din clasa i prezise ca j. Pentru clasificare binară:
| Prezis: negativ | Prezis: pozitiv | |
|---|---|---|
| Real: negativ | TN | FP (alarmă falsă) |
| Real: pozitiv | FN (ratat) | TP |
Interpretare
Diagonala = corect; restul = erori, defalcate pe tip. La multi-clasă vezi imediat care perechi de clase se confundă (de exemplu cifrele 3 și 8) — informație care îți spune ce feature-uri să adaugi. Din matrice derivă direct precizia și recall-ul fiecărei clase (lecția 4.1).
from sklearn.metrics import confusion_matrix, ConfusionMatrixDisplay
cm = confusion_matrix(y_val, y_pred)
ConfusionMatrixDisplay(cm, display_labels=model.classes_).plot(cmap="Blues")
Curba ROC și AUC
Clasificatorul dă probabilități; pragul (implicit 0.5) le transformă în clase. Curba ROC arată, pentru toate pragurile posibile, compromisul dintre rata adevărat-pozitivelor (recall) și rata fals-pozitivelor:
TPR = TP/(TP+FN) — cât din pozitivele reale prindem (axa Y)
FPR = FP/(FP+TN) — cât din negativele reale alarmăm din greșeală (axa X)
AUC (aria de sub curbă): 1.0 = separare perfectă, 0.5 = ghicit la întâmplare (diagonala). AUC nu depinde de prag — măsoară cât de bine ordonează modelul exemplele.
Utilizare pentru clasificare — alegerea pragului
from sklearn.metrics import roc_curve, roc_auc_score
import matplotlib.pyplot as plt
proba = model.predict_proba(X_val)[:, 1]
fpr, tpr, praguri = roc_curve(y_val, proba)
print("AUC:", roc_auc_score(y_val, proba))
plt.plot(fpr, tpr); plt.plot([0, 1], [0, 1], "--", c="gray")
plt.xlabel("FPR"); plt.ylabel("TPR"); plt.show()
# prag personalizat: prindem mai multe pozitive, acceptăm mai multe alarme
pred_strict = (proba >= 0.3).astype(int)
Problemă rezolvată: diagnoza completă a unui clasificator medical
Continuăm problema din lecția 2.2: modelul e antrenat, acum îl anatomizăm — matrice de confuzie, curbă ROC, alegerea pragului optim pentru F1.
Rezolvarea completă
import numpy as np
from sklearn.metrics import (confusion_matrix, ConfusionMatrixDisplay,
roc_curve, roc_auc_score, f1_score)
proba = model.predict_proba(X_val)[:, 1]
# 1. matricea de confuzie la pragul implicit
cm = confusion_matrix(y_val, proba >= 0.5)
print(cm) # de ex. [[85 8]
# [17 25]] → 17 diabetici ratați!
# 2. curba ROC + AUC
print("AUC:", roc_auc_score(y_val, proba).round(3))
# 3. pragul care maximizează F1 pe validare
praguri = np.linspace(0.1, 0.9, 81)
f1s = [f1_score(y_val, proba >= p) for p in praguri]
best = praguri[int(np.argmax(f1s))]
print("Prag optim:", best.round(2), "F1:", max(f1s).round(3))
cm2 = confusion_matrix(y_val, proba >= best)
print(cm2) # FN scade — mai puțini bolnavi ratați
Concluzia: același model, prag ales inteligent → F1 mai mare și mai puține cazuri ratate. Nimic din model nu s-a schimbat — doar citirea probabilităților.
Probleme propuse
Din y_real = [A,A,B,B,B,C,C,A,B,C] și y_pred = [A,B,B,B,C,C,C,A,B,A], construiește matricea de confuzie 3×3 pe hârtie. Care clasă are cel mai slab recall?
Pentru pragul 0.5, TPR = 0.8 și FPR = 0.1. Marchează punctul pe o schiță de curbă ROC. Ce se întâmplă cu ambele rate când cobori pragul la 0.2?
Antrenează un clasificator pe digits și afișează matricea de confuzie 10×10. Care două cifre se confundă cel mai des? Afișează câteva imagini greșit clasificate.
Pe o problemă binară punctată cu F1, compară scorul submisiei cu prag 0.5 vs pragul optimizat pe validare locală.