A la lliçó anterior vam aprendre amb quines dades avaluar un model; ara toca decidir amb quin número. Fins al moment hem usat l'accuracy (classificació) i l'MSE (regressió) de manera instrumental, sense qüestionar-los. Això s'acaba aquí: veurem que l'accuracy pot ser un parany descarat amb classes desequilibrades —el churn de MercaFresh volta el 20 %—, que la matriu de confusió distingeix tipus d'error amb costos de negoci molt diferents (què és pitjor: trucar a un client fidel o perdre'n un que estava a punt de marxar?), i que en regressió conviuen diverses mètriques (MAE, MSE, RMSE, R²) amb interpretacions i unitats diferents. Tancarem amb els models dummy, la materialització en scikit-learn del concepte de baseline que vam introduir a la lliçó 01-04: cap mètrica no significa res en el buit; només significa alguna cosa comparada amb una referència.

Contingut

  1. La matriu de confusió: els quatre destins d'una predicció
  2. L'accuracy i el seu parany amb el desequilibri
  3. Precision, recall i F1: fórmules i interpretació de negoci
  4. classification_report i elecció de mètrica segons el problema
  5. Mètriques de regressió: MAE, MSE, RMSE i R²
  6. El baseline: DummyClassifier i DummyRegressor

La matriu de confusió: els quatre destins d'una predicció

En un problema binari com el churn (1 = el client es dona de baixa, 0 = es queda), cada predicció pot acabar en un de quatre destins, segons què va predir el model i què va passar en realitat:

Predit: churn (1) Predit: es queda (0)
Real: churn (1) TP (veritable positiu) FN (fals negatiu)
Real: es queda (0) FP (fals positiu) TN (veritable negatiu)
  • TP (true positive): vam predir churn i el client efectivament va marxar. Encert.
  • TN (true negative): vam predir que es quedava i es va quedar. Encert.
  • FP (fals positiu): vam predir churn, però el client era fidel. És la "falsa alarma": MercaFresh gasta una trucada i potser un descompte en algú que no pensava marxar.
  • FN (fals negatiu): vam predir que es quedava i va marxar. L'error més car aquí: perdem el client sense haver intentat retenir-lo.

Això no és nou per a tu: a la lliçó 02-05, amb el teorema de Bayes, vam analitzar un detector amb falsos positius i vam veure que el cost de cada tipus d'error és diferent i que amb esdeveniments poc freqüents les falses alarmes poden dominar. La matriu de confusió és exactament aquella anàlisi, aplicada a un classificador.

from sklearn.linear_model import LogisticRegression
from sklearn.metrics import confusion_matrix, ConfusionMatrixDisplay
from sklearn.model_selection import train_test_split

X_entrenament, X_prova, y_entrenament, y_prova = train_test_split(
    X, y, test_size=0.2, random_state=42, stratify=y  # com a 06-01
)

model = LogisticRegression(max_iter=1000)
model.fit(X_entrenament, y_entrenament)
y_pred = model.predict(X_prova)

cm = confusion_matrix(y_prova, y_pred)
print(cm)
# [[TN  FP]
#  [FN  TP]]   <- compte: sklearn ordena les classes 0, 1 (files = real, columnes = predit)

ConfusionMatrixDisplay(cm, display_labels=["Es queda", "Churn"]).plot()

Suposem que sobre 2.000 clients de prova obtenim:

Pred: churn Pred: es queda
Real: churn (400) TP = 240 FN = 160
Real: es queda (1.600) FP = 120 TN = 1.480

Tota mètrica de classificació binària es calcula a partir d'aquests quatre números.

L'accuracy i el seu parany amb el desequilibri

L'accuracy és la fracció d'encerts totals:

$$\text{accuracy} = \frac{TP + TN}{TP + TN + FP + FN} = \frac{240 + 1480}{2000} = 0.86$$

Un 86 % sona bé... fins que recordem el desequilibri. Amb un churn del 20 %, un "model" absurd que predigui sempre "es queda" encerta el 80 % de les vegades:

import numpy as np
y_pred_gandul = np.zeros_like(y_prova)       # sempre prediu "es queda"
print((y_pred_gandul == y_prova).mean())     # aprox. 0.80

Aquell model té un 80 % d'accuracy i és completament inútil: no detecta ni un sol client en fuga (TP = 0). El parany s'agreuja com més gran és el desequilibri: en detecció de frau amb un 1 % de positius, "mai no hi ha frau" assoleix un 99 % d'accuracy. Moralitat: amb classes desequilibrades, l'accuracy per si sol enganya; necessitem mètriques que mirin cada classe per separat.

Precision, recall i F1: fórmules i interpretació de negoci

Precision: quan el model dona l'alarma, encerta?

$$\text{precision} = \frac{TP}{TP + FP} = \frac{240}{240 + 120} = 0.67$$

De tots els clients que el model va assenyalar com a churn, quina fracció marxava de veritat? A MercaFresh: si l'equip de retenció truca als assenyalats, la precision mesura quin percentatge de trucades no es malbarata. Una precision baixa significa moltes falses alarmes: cost de campanya llençat en clients fidels (i el risc de molestar-los).

Recall: dels que marxen, quants en cacem?

$$\text{recall} = \frac{TP}{TP + FN} = \frac{240}{240 + 160} = 0.60$$

De tots els clients que realment es van donar de baixa, quina fracció va detectar el model? Un recall del 60 % significa que el 40 % de les fugues reals passen desapercebudes: clients que es perden sense que ningú no intentés retenir-los. També s'anomena sensibilitat o taxa de veritables positius (amb aquest nom reapareixerà a la corba ROC de 06-04).

L'estira-i-arronsa, i la pregunta de negoci

Precision i recall estan en tensió: per pujar el recall cal assenyalar més clients (alarma més sensible), cosa que genera més falsos positius i abaixa la precision, i viceversa. Quina prioritzar? Depèn dels costos:

  • Cost d'un FP: una trucada de l'equip de retenció més, potser, un val de 10 €. Barat.
  • Cost d'un FN: perdre un client el valor anual mitjà del qual a MercaFresh pot ser de centenars d'euros. Car.

Amb aquesta estructura de costos, en el churn sol interessar prioritzar el recall: millor unes quantes trucades de més que clients valuosos escapant-se en silenci. En altres problemes és al revés (un filtre de spam amb precision baixa enterra correus legítims). A 06-04 veurem que el llindar de decisió de la regressió logística (04-02) és precisament la palanca per moure aquest equilibri.

F1: el resum en un número

Quan es necessita una sola xifra que combini totes dues, s'usa la mitjana harmònica de precision i recall:

$$F_1 = 2 \cdot \frac{\text{precision} \cdot \text{recall}}{\text{precision} + \text{recall}} = 2 \cdot \frac{0.67 \cdot 0.60}{0.67 + 0.60} \approx 0.63$$

La mitjana harmònica penalitza els desequilibris: si una de les dues és propera a 0, l'F1 s'enfonsa encara que l'altra sigui perfecta (a diferència de la mitjana aritmètica). Un model només té bon F1 si és raonable en totes dues.

from sklearn.metrics import accuracy_score, precision_score, recall_score, f1_score

print("Accuracy :", accuracy_score(y_prova, y_pred))
print("Precision:", precision_score(y_prova, y_pred))
print("Recall   :", recall_score(y_prova, y_pred))
print("F1       :", f1_score(y_prova, y_pred))

classification_report i elecció de mètrica segons el problema

scikit-learn resumeix tot l'anterior, per classe, en una sola crida:

from sklearn.metrics import classification_report
print(classification_report(y_prova, y_pred, target_names=["Es queda", "Churn"]))
              precision    recall  f1-score   support

    Es queda       0.90      0.93      0.91      1600
       Churn       0.67      0.60      0.63       400

    accuracy                           0.86      2000
   macro avg       0.78      0.76      0.77      2000
weighted avg       0.85      0.86      0.86      2000

Com llegir-lo:

  • Cada fila dona precision/recall/F1 tractant aquella classe com a "positiva". support és quants exemples reals hi ha d'aquella classe a la prova.
  • macro avg: mitjana simple de les classes (totes pesen igual, útil amb desequilibri per no amagar la classe minoritària).
  • weighted avg: mitjana ponderada per support (amb desequilibri s'assembla a l'accuracy i pot maquillar una classe minoritària dolenta).
  • Fixa't que la classe majoritària llueix un 0.91 d'F1 mentre el churn es queda en 0.63: l'informe per classes destapa allò que l'accuracy global amagava.

Quina mètrica triar? Una guia pràctica:

Situació Mètrica principal Per què
Classes equilibrades, errors de cost similar Accuracy Simple i suficient
El cost alt és la falsa alarma (spam, bloquejar compres legítimes) Precision Minimitzar FP
El cost alt és el positiu no detectat (churn, diagnòstic, frau) Recall Minimitzar FN
Desequilibri i es vol un sol número equilibrat F1 Combina P i R
Comparar models independentment del llindar ROC-AUC Lliçó 06-04

Mètriques de regressió: MAE, MSE, RMSE i R²

Canviem de problema: la predicció de la despesa mensual de cada client de MercaFresh, la regressió que vam plantejar a 04-01. Aquí no hi ha encerts i errades, sinó distàncies entre el que s'ha predit ($\hat{y}_i$) i el que és real ($y_i$).

  • MAE (error absolut mitjà): $\frac{1}{n}\sum |y_i - \hat{y}_i|$. Es llegeix directament en les unitats del target: "ens equivoquem, de mitjana, en 18 € al mes". Tracta tots els errors per igual.
  • MSE (error quadràtic mitjà): $\frac{1}{n}\sum (y_i - \hat{y}_i)^2$. En elevar al quadrat, penalitza molt més els errors grans (un error de 100 € pesa com 100 errors de 10 €) i les seves unitats són €², poc interpretables. És la mètrica que la regressió lineal minimitza internament (04-01).
  • RMSE: $\sqrt{MSE}$. Recupera les unitats originals (€) mantenint la sensibilitat als errors grans. Sempre RMSE ≥ MAE; una bretxa gran entre tots dos delata l'existència d'errors puntuals enormes (outliers).
  • (coeficient de determinació): fracció de la variància del target que el model explica. 1.0 = predicció perfecta; 0.0 = tan bo com predir sempre la mitjana; pot ser negatiu en prova si el model és pitjor que la mitjana. És adimensional, cosa que permet comparar problemes amb escales diferents.
from sklearn.linear_model import LinearRegression
from sklearn.metrics import mean_absolute_error, mean_squared_error, r2_score
import numpy as np

reg = LinearRegression().fit(X_entrenament_d, y_entrenament_d)   # despesa mensual (EUR)
y_pred_d = reg.predict(X_prova_d)

mae  = mean_absolute_error(y_prova_d, y_pred_d)
mse  = mean_squared_error(y_prova_d, y_pred_d)
rmse = np.sqrt(mse)
r2   = r2_score(y_prova_d, y_pred_d)

print(f"MAE : {mae:.2f} EUR      <- error mitja 'tipic'")
print(f"MSE : {mse:.2f} EUR^2    <- dificil d'interpretar directament")
print(f"RMSE: {rmse:.2f} EUR      <- com el MAE pero penalitza errors grans")
print(f"R^2 : {r2:.3f}           <- fraccio de variancia explicada")
Mètrica Unitats Sensible a outliers Quan preferir-la
MAE Les del target (€) No especialment Interpretació directa; els errors grans no són "pitjors per unitat"
MSE Target² (€²) Molt Optimització interna; comparació tècnica
RMSE Les del target (€) Molt Reportar quan els errors grans són especialment costosos
Sense unitats Moderada Comunicar "quant explica" el model; comparar datasets

A MercaFresh, un MAE de 18 € sobre una despesa mitjana de 120 € mensuals (~15 % d'error relatiu) és un missatge que el negoci entén de seguida; un MSE de 850 €², no.

El baseline: DummyClassifier i DummyRegressor

A la lliçó 01-04 vam introduir el concepte de baseline: abans de celebrar qualsevol mètrica, cal preguntar-se "millor que què?". scikit-learn ho materialitza amb models deliberadament ximples:

from sklearn.dummy import DummyClassifier, DummyRegressor
from sklearn.metrics import f1_score, mean_absolute_error

# Classificacio: predir sempre la classe majoritaria ("es queda")
dummy_clf = DummyClassifier(strategy="most_frequent")
dummy_clf.fit(X_entrenament, y_entrenament)
print("Accuracy dummy:", dummy_clf.score(X_prova, y_prova))              # aprox. 0.80
print("F1 dummy      :", f1_score(y_prova, dummy_clf.predict(X_prova)))  # 0.0 !

# Regressio: predir sempre la despesa mitjana
dummy_reg = DummyRegressor(strategy="mean")
dummy_reg.fit(X_entrenament_d, y_entrenament_d)
print("MAE dummy:", mean_absolute_error(y_prova_d, dummy_reg.predict(X_prova_d)))

La lectura és reveladora: el dummy assoleix un 80 % d'accuracy (el parany del desequilibri, quantificat!) però un F1 de 0 a la classe churn. El nostre model real, amb un 86 % d'accuracy, només millora el dummy en 6 punts d'accuracy... però passa de 0.0 a 0.63 d'F1, que és on hi ha el valor real. Regles pràctiques:

  • Calcula sempre el baseline dummy abans d'avaluar el teu primer model.
  • Reporta les mètriques del teu model al costat de les del baseline: "MAE de 18 € davant de 41 € del baseline de la mitjana" és un resultat; "MAE de 18 €" a seques, no.
  • Si el teu model no supera clarament el dummy, alguna cosa falla: features sense senyal, fuita en direcció contrària, un bug... o un problema que simplement no es pot predir amb aquestes dades.

Errors Comuns i Consells

  • Reportar només accuracy amb classes desequilibrades. És l'error estrella. Acompanya'l sempre de la matriu de confusió i de l'F1 (o precision/recall) de la classe minoritària.
  • Confondre precision amb recall. Truc mnemotècnic: precision = de les meves prediccions positives, quantes eren correctes?; recall = dels positius reals, quants en vaig recuperar?
  • Triar la mètrica després de veure els resultats. Decidir "la meva mètrica és la que em surt millor" és autoengany. Fixa la mètrica (amb el negoci) abans de comparar models.
  • Interpretar l'MSE en unitats del target. L'MSE està en unitats al quadrat; per comunicar usa MAE o RMSE.
  • Assumir que R² alt = model útil. Un R² de 0.95 amb fuita de dades (06-01) no val res; i un R² de 0.3 pot ser valuosíssim en un problema molt sorollós, si supera amb claredat el baseline.
  • Consell: la matriu de confusió és la teva radiografia per defecte: gairebé qualsevol dubte sobre un classificador binari ("on falla?, a qui confon?") es respon mirant-la abans que cap mètrica agregada.

Exercicis

Exercici 1

Un model de churn avaluat sobre 1.000 clients (200 churn reals) produeix: TP = 150, FN = 50, FP = 100, TN = 700. Calcula a mà accuracy, precision, recall i F1. Quin accuracy tindria el dummy de classe majoritària? Val la pena el model?

Exercici 2

MercaFresh avalua dos models de despesa mensual. Model A: MAE = 15 €, RMSE = 45 €. Model B: MAE = 18 €, RMSE = 22 €. Explica què revela la diferència entre MAE i RMSE de cada model i raona quin triaries si els errors grans de predicció (p. ex., infraestimar en 200 € la despesa d'un gran client) són especialment costosos.

Exercici 3

Escriu el codi que entrena una LogisticRegression i un DummyClassifier(strategy="most_frequent") sobre X_entrenament, y_entrenament (churn), i per a tots dos imprimeix el classification_report sobre prova. Indica quins dos números de l'informe compararies per decidir si el model aporta valor.

Solucions

Solució 1.

  • Accuracy = (150 + 700) / 1000 = 0.85
  • Precision = 150 / (150 + 100) = 0.60
  • Recall = 150 / (150 + 50) = 0.75
  • F1 = 2 · (0.60 · 0.75) / (0.60 + 0.75) = 0.9 / 1.35 ≈ 0.67
  • Dummy majoritari: encerta els 800 "es queda" → accuracy = 0.80.

El model només guanya 5 punts d'accuracy al dummy, però això és enganyós a favor del dummy: el model detecta el 75 % de les fugues reals (el dummy, el 0 %). Amb el cost asimètric del churn (perdre un client ≫ una trucada de més), sí que val la pena, i el recall de 0.75 amb precision 0.60 és un compromís raonable per a una campanya de retenció.

Solució 2. La bretxa RMSE − MAE mesura quant pesen els errors grans. El model A té millor error típic (MAE 15 < 18) però un RMSE triple que el seu MAE (45 vs. 15): comet errors puntuals molt grans. El model B és una mica pitjor "en el dia a dia" però els seus errors són homogenis (22 vs. 18: sense catàstrofes). Si els errors grans són especialment costosos, es tria el model B: sacrifica 3 € d'error mitjà a canvi d'eliminar les errades extremes.

Solució 3.

from sklearn.linear_model import LogisticRegression
from sklearn.dummy import DummyClassifier
from sklearn.metrics import classification_report

model = LogisticRegression(max_iter=1000).fit(X_entrenament, y_entrenament)
dummy = DummyClassifier(strategy="most_frequent").fit(X_entrenament, y_entrenament)

for nom, m in [("Regressio logistica", model), ("Dummy", dummy)]:
    print(f"===== {nom} =====")
    print(classification_report(y_prova, m.predict(X_prova),
                                target_names=["Es queda", "Churn"],
                                zero_division=0))

Compararia sobretot el recall i l'F1 de la classe "Churn": en el dummy són 0.0 (no assenyala ningú), així que qualsevol valor clarament positiu del model demostra que aporta capacitat real de detecció, cosa que l'accuracy (0.80 vs. ~0.86) amb prou feines deixa veure.

Conclusió

Ja sabem mesurar: la matriu de confusió separa els quatre destins d'una predicció i connecta amb l'anàlisi de costos d'errors que vam fer amb Bayes a 02-05; l'accuracy enganya amb el desequilibri del churn; precision i recall tradueixen els errors a llenguatge de negoci (trucades malbaratades davant de clients perduts) i l'F1 els resumeix; en regressió, MAE/RMSE parlen en euros i l'R² en variància explicada; i el DummyClassifier/DummyRegressor converteix el baseline de 01-04 en codi, donant context a qualsevol xifra. Però totes aquestes mètriques les hem calculades sobre una única divisió entrenament/prova, i aquella divisió depèn de l'atzar d'una llavor: amb un altre random_state, altres números. Fins a quin punt és fiable, doncs, una mètrica calculada una sola vegada? Aquesta inquietud té nom i solució —la validació creuada— i és exactament el tema de la propera lliçó.

Curs de Machine Learning

Mòdul 1: Introducció al Machine Learning

Mòdul 2: Fonaments d'Estadística i Probabilitat

Mòdul 3: Preprocessament de Dades

Mòdul 4: Algorismes de Machine Learning Supervisat

Mòdul 5: Algorismes de Machine Learning No Supervisat

Mòdul 6: Avaluació i Validació de Models

Mòdul 7: Tècniques Avançades i Optimització

Mòdul 8: Implementació i Desplegament de Models

Mòdul 9: Projectes Pràctics

Mòdul 10: Recursos Addicionals

© Copyright 2026. Tots els drets reservats