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
- La matriu de confusió: els quatre destins d'una predicció
- L'accuracy i el seu parany amb el desequilibri
- Precision, recall i F1: fórmules i interpretació de negoci
classification_reporti elecció de mètrica segons el problema- Mètriques de regressió: MAE, MSE, RMSE i R²
- 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.80Aquell 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 2000Com 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 persupport(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).
- R² (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 |
| R² | 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
- Què és el Machine Learning?
- Història i evolució del Machine Learning
- Tipus de Machine Learning
- Aplicacions del Machine Learning
- El flux de treball d'un projecte de Machine Learning
Mòdul 2: Fonaments d'Estadística i Probabilitat
- Conceptes bàsics d'estadística
- Distribucions de probabilitat
- Correlació i covariància
- Inferència estadística
- Teorema de Bayes
Mòdul 3: Preprocessament de Dades
- Neteja de dades
- Gestió de dades mancants
- Transformació de dades
- Codificació de variables categòriques
- Normalització i estandardització
- Enginyeria de característiques
Mòdul 4: Algorismes de Machine Learning Supervisat
- Regressió lineal
- Regressió logística
- Arbres de decisió
- Màquines de suport vectorial (SVM)
- K veïns més propers (K-NN)
- Naive Bayes
- Xarxes neuronals
Mòdul 5: Algorismes de Machine Learning No Supervisat
- Clustering: K-means
- Clustering jeràrquic
- Anàlisi de components principals (PCA)
- Anàlisi d'agrupament DBSCAN
- Visualització de dades amb t-SNE i UMAP
Mòdul 6: Avaluació i Validació de Models
- Divisió de dades: entrenament, validació i prova
- Mètriques d'avaluació
- Validació creuada
- Corba ROC i AUC
- Overfitting i underfitting
Mòdul 7: Tècniques Avançades i Optimització
- Regularització: Ridge, Lasso i Elastic Net
- Ensemble Learning
- Gradient Boosting
- Xarxes neuronals profundes (Deep Learning)
- Optimització d'hiperparàmetres
Mòdul 8: Implementació i Desplegament de Models
- Frameworks i biblioteques populars
- Implementació de models en producció
- Manteniment i monitoratge de models
- Consideracions ètiques i de privadesa
Mòdul 9: Projectes Pràctics
- Projecte 1: Predicció de preus d'habitatges
- Projecte 2: Classificació d'imatges
- Projecte 3: Anàlisi de sentiments a les xarxes socials
- Projecte 4: Detecció de fraus
- Projecte 5: Segmentació de clients
