A la lliçó anterior vam deixar presentat el boosting com la família seqüencial dels ensembles: models que s'entrenen l'un rere l'altre, cadascun corregint els errors de l'anterior. Aquesta lliçó la dediquem per complet al seu representant estrella, el gradient boosting, probablement l'algorisme més guanyador de l'última dècada en dades tabulars: domina les competicions de Kaggle i resol en producció problemes exactament com el churn i la demanda de MercaFresh. Entendràs la seva mecànica amb un exemple numèric a mà, aprendràs a manejar els seus dos controls principals (learning rate i nombre d'estimadors), coneixeràs les implementacions que importen — sklearn, HistGradientBoosting, XGBoost, LightGBM — i l'enfrontaràs al Random Forest de la lliçó anterior.
Contingut
- La idea: aprendre dels residus
- Exemple numèric a mà: 3 iteracions
- Learning rate i n_estimators: l'equilibri
- Gradient boosting a scikit-learn
- HistGradientBoosting: la versió moderna
- XGBoost i LightGBM: els dominadors del tauler
- Boosting sobre el churn de MercaFresh: duel amb Random Forest
- El taló d'Aquil·les: overfitting i els seus frens
- Interpretació: feature importance i SHAP
La idea: aprendre dels residus
Random Forest entrena arbres independents i promitja. Gradient boosting fa el contrari: entrena arbres petits i febles en cadena, on cadascun té una única missió: predir l'error que van deixar els anteriors.
En regressió, amb error quadràtic, el procés és molt intuïtiu:
- Comença amb una predicció trivial: la mitjana de
y(el nostre vell conegutDummyRegressorde 06-02). - Calcula els residus:
residu = y_real - prediccio_actual. - Entrena un arbre petit que predigui aquests residus a partir de les features.
- Actualitza:
prediccio_nova = prediccio_actual + η · prediccio_de_l_arbre, on η (eta) és el learning rate, un factor que encongeix cada correcció. - Torna al pas 2, tantes vegades com digui
n_estimators.
El nom "gradient" ve del fet que els residus són, matemàticament, el gradient (amb el signe canviat) de la funció de pèrdua quadràtica: cada arbre fa un pas de descens de gradient — el mateix que vam usar a 04-01 per ajustar la regressió lineal — però en l'espai de les prediccions en lloc de l'espai dels coeficients. Amb altres pèrdues (p. ex. logística per a classificació) se segueix el mateix esquema substituint el residu pel "pseudoresidu" corresponent; per això el mètode generalitza a classificació sense canviar de filosofia.
flowchart LR
M0[Prediccio inicial: mitjana] --> R1[Residus 1]
R1 --> A1[Arbre 1 apren residus]
A1 --> M1[Prediccio += eta x arbre 1]
M1 --> R2[Residus 2 mes petits]
R2 --> A2[Arbre 2]
A2 --> M2[Prediccio += eta x arbre 2]
M2 --> R3[Residus 3 encara menors]
Exemple numèric a mà: 3 iteracions
Prenguem 4 clients de MercaFresh i la seva despesa mensual (en €). Per poder seguir els comptes usarem learning rate η = 1 (sense encongiment) i "arbres" simplificats que prediuen la mitjana del residu del seu grup (clients de freqüència alta vs. baixa):
| Client | Freqüència | Despesa real (y) |
|---|---|---|
| Anna | alta | 120 |
| Bruno | alta | 100 |
| Carla | baixa | 40 |
| David | baixa | 60 |
Iteració 0. Predicció inicial = mitjana global = (120+100+40+60)/4 = 80 per a tots.
| Client | Predicció | Residu (y − pred) |
|---|---|---|
| Anna | 80 | +40 |
| Bruno | 80 | +20 |
| Carla | 80 | −40 |
| David | 80 | −20 |
Iteració 1. L'arbre 1 divideix per freqüència i prediu la mitjana del residu de cada grup: +30 per a freqüència alta, −30 per a baixa. Actualitzem:
| Client | Predicció nova | Residu nou |
|---|---|---|
| Anna | 80 + 30 = 110 | +10 |
| Bruno | 80 + 30 = 110 | −10 |
| Carla | 80 − 30 = 50 | −10 |
| David | 80 − 30 = 50 | +10 |
L'error s'ha reduït dràsticament: de residus ±40/±20 a ±10.
Iteració 2. Dins de cada grup els residus ja sumen zero, així que un arbre que només veiés la freqüència prediria 0; suposem que l'arbre 2 troba una altra feature (p. ex. l'antiguitat) que separa l'Anna d'en Bruno i en David de la Carla, i prediu +10/−10 segons correspongui:
| Client | Predicció final | Residu |
|---|---|---|
| Anna | 110 + 10 = 120 | 0 |
| Bruno | 110 − 10 = 100 | 0 |
| Carla | 50 − 10 = 40 | 0 |
| David | 50 + 10 = 60 | 0 |
Tres passos (predicció base + 2 arbres) i l'entrenament està clavat. I aquí hi ha la moralitat doble: la suma de correctors febles assoleix una precisió que cap no aconseguiria sol… però també acabem de veure com de ràpid aquest mètode pot memoritzar el conjunt d'entrenament — amb residu zero en entrenament, tot el que quedi és ajust al soroll. A la pràctica, η = 1 gairebé no s'usa mai: encongir cada pas és el primer fre contra l'overfitting.
Learning rate i n_estimators: l'equilibri
Els dos controls principals estan acoblats:
learning_rate(η): quant aporta cada arbre. Valors típics: 0.01–0.3.n_estimators: quants arbres s'encadenen.
La relació és de compensació: si redueixes η a la meitat, necessites aproximadament el doble d'arbres per arribar al mateix punt. Per què molestar-se llavors a abaixar η? Perquè molts passos petits generalitzen millor que pocs passos grans: cada correcció suau deixa marge als arbres següents per esmenar el rumb, mentre que un pas gran pot perseguir soroll irreversiblement.
| Configuració | Comportament |
|---|---|
| η alt (0.3) + pocs arbres | Ràpid d'entrenar; risc d'overfitting i de passos bruscos |
| η baix (0.01–0.05) + molts arbres | Més lent; millor generalització; necessita early stopping per no passar-se |
| η alt + molts arbres | Recepta gairebé segura d'overfitting |
A diferència del Random Forest — on més arbres només estabilitzava —, en boosting n_estimators sí que és un control de complexitat: cada arbre addicional continua reduint l'error d'entrenament, i a partir d'un cert punt comença a pujar el de validació. És exactament la silueta de les corbes de 06-05, i el seu antídot natural serà l'early stopping que veurem de seguida.
Gradient boosting a scikit-learn
La implementació clàssica: GradientBoostingRegressor i GradientBoostingClassifier.
from sklearn.ensemble import GradientBoostingClassifier
gb = GradientBoostingClassifier(
n_estimators=300, # arbres encadenats
learning_rate=0.05, # aportacio de cada arbre
max_depth=3, # arbres deliberadament petits (febles)
subsample=0.8, # cada arbre veu el 80% de les files (toc de bagging)
random_state=42,
)Fixa't en max_depth=3: en boosting els arbres són nans a propòsit (1–4 nivells). L'aprenent feble és una decisió de disseny: la potència ve de la seqüència, no de l'individu. subsample < 1 afegeix aleatorietat a l'estil bagging ("stochastic gradient boosting"), que sol millorar la generalització.
HistGradientBoosting: la versió moderna
Des de scikit-learn 0.21 existeix una reimplementació molt més ràpida: HistGradientBoostingClassifier/Regressor. El seu truc és discretitzar cada feature en un histograma de com a màxim 255 contenidors, de manera que cercar la millor divisió ja no requereix ordenar valors continus: es recorren els contenidors. En datasets de desenes de milers de files és ordres de magnitud més ràpida, i a més:
- Maneja valors mancants de manera nativa (aprèn cap a quina branca enviar els NaN, sense imputació prèvia — tot i que el que vam aprendre a 03-02 continua sent necessari per a la resta de models).
- Incorpora early stopping integrat (
early_stopping=True) amb una fracció de validació interna. - Suporta features categòriques natives (
categorical_features).
from sklearn.ensemble import HistGradientBoostingClassifier
hgb = HistGradientBoostingClassifier(
learning_rate=0.05,
max_iter=1000, # equivalent a n_estimators
early_stopping=True, # deixa d'afegir arbres quan la validacio no millora
validation_fraction=0.15,
n_iter_no_change=20, # paciencia: 20 iteracions sense millora
random_state=42,
)Regla pràctica actual: per a gradient boosting dins de l'ecosistema sklearn, usa la versió Hist per defecte; la clàssica queda per a datasets petits o per compatibilitat.
XGBoost i LightGBM: els dominadors del tauler
Fora de sklearn viuen les dues biblioteques que van popularitzar el gradient boosting modern (s'instal·len a part: pip install xgboost lightgbm):
| XGBoost (2014) | LightGBM (2017) | |
|---|---|---|
| Aportació clau | Regularització L1/L2 en els arbres, maneig de mancants, paral·lelització eficient | Creixement per fulles (leaf-wise) i histogrames: encara més ràpid i amb menys memòria |
| Fama | L'algorisme que "guanyava tots els Kaggle" a mitjans dels 2010 | Estàndard actual en indústria per a tabular gran |
| API | Pròpia + wrapper compatible amb sklearn (XGBClassifier) |
Ídem (LGBMClassifier) |
Per què aquesta família domina en dades tabulars (taules de clients, transaccions, sensors…)? Perquè els arbres capturen sense esforç interaccions i no-linealitats, ignoren l'escala de les features, digereixen barreges de variables numèriques i categòriques, i el boosting esprem fins a l'última gota de senyal — tot amb temps d'entrenament de segons o minuts. En aquest terreny solen batre fins i tot les xarxes profundes, com discutirem amb honestedat a 07-04.
Totes dues biblioteques ofereixen early stopping contra un conjunt de validació explícit, la manera professional de fixar n_estimators:
# Exemple amb l'API sklearn d'XGBoost
from xgboost import XGBClassifier
xgb = XGBClassifier(n_estimators=2000, learning_rate=0.05, max_depth=3,
early_stopping_rounds=50, eval_metric="logloss")
xgb.fit(X_train, y_train, eval_set=[(X_val, y_val)], verbose=False)
print(xgb.best_iteration) # quants arbres s'han usat realmentEs demana un n_estimators deliberadament alt i es deixa que la validació decideixi on parar: si després de 50 rondes la mètrica no millora, s'atura i es queda amb la millor iteració. Observa que reapareix la disciplina de 06-01: el conjunt de validació usat per parar no pot ser la prova final.
Boosting sobre el churn de MercaFresh: duel amb Random Forest
Enfrontem el campió de la lliçó anterior amb el nou aspirant, sobre el mateix dataset de churn amb features RFM i la mateixa validació creuada estratificada de 06-03.
import numpy as np
import pandas as pd
from sklearn.model_selection import StratifiedKFold, cross_val_score
from sklearn.ensemble import (RandomForestClassifier,
HistGradientBoostingClassifier)
# Dataset de churn de MercaFresh (identic al de 07-02)
rng = np.random.default_rng(42)
n = 1000
recencia = rng.gamma(2, 15, n)
frequencia = rng.poisson(5, n) + 1
monetari = rng.gamma(3, 40, n)
antiguitat = rng.uniform(1, 60, n)
incidencies = rng.poisson(0.5, n)
logits = 0.05 * recencia - 0.4 * frequencia + 0.6 * incidencies - 0.01 * antiguitat - 0.5
y = (rng.random(n) < 1 / (1 + np.exp(-logits))).astype(int)
X = pd.DataFrame({"recencia": recencia, "frequencia": frequencia,
"monetari": monetari, "antiguitat": antiguitat,
"incidencies": incidencies})
cv = StratifiedKFold(n_splits=5, shuffle=True, random_state=42)
models = {
"Random Forest (07-02)": RandomForestClassifier(
n_estimators=300, random_state=42, n_jobs=-1),
"HistGradientBoosting": HistGradientBoostingClassifier(
learning_rate=0.05, max_iter=500, max_depth=3,
early_stopping=True, random_state=42),
}
for nom, model in models.items():
f1 = cross_val_score(model, X, y, cv=cv, scoring="f1")
print(f"{nom:24s} F1: {f1.mean():.3f} +/- {f1.std():.3f}")En datasets petits i amb senyal senzill com aquest, tots dos solen quedar molt igualats (de vegades guanya el bosc). El patró general a la pràctica és:
- Random Forest: excel·lent resultat amb zero ajust; difícil d'espatllar. La baseline forta.
- Gradient boosting: sostre més alt — amb els seus hiperparàmetres ben triats sol gratar uns punts més de mètrica, especialment en datasets grans amb interaccions complexes — però exigeix aquest ajust (que automatitzarem a 07-05) i vigilància de l'overfitting.
Per a MercaFresh la lectura de negoci és concreta: si el bosc dona F1 0.82 sense esforç i el boosting ben afinat dona 0.85, aquests tres punts són desenes de clients recuperables cada mes correctament prioritzats per la campanya de retenció — normalment mereix l'esforç.
El taló d'Aquil·les: overfitting i els seus frens
El boosting persegueix residus, i els residus acaben sent soroll: si el deixes córrer, memoritza l'entrenament (ho vam veure a l'exemple a mà, que va arribar a residu zero). És l'alumne avantatjat de les patologies de 06-05, i per això ve equipat amb més frens que cap altre algorisme:
| Fre | Paràmetre típic | Efecte |
|---|---|---|
| Learning rate baix | learning_rate=0.01–0.1 |
Passos petits, correccions suaus |
| Early stopping | early_stopping / early_stopping_rounds |
Talla la seqüència quan la validació deixa de millorar |
| Arbres petits | max_depth=2–4 (o num_leaves baix a LightGBM) |
Limita la complexitat de cada corrector |
| Submostreig de files | subsample<1 |
Aleatorietat estil bagging, descorrelaciona errors |
| Submostreig de columnes | colsample_bytree<1 (XGBoost/LightGBM) |
Feature bagging, com a Random Forest |
| Regularització a les fulles | reg_alpha, reg_lambda (XGBoost/LightGBM) |
L'L1/L2 de 07-01 aplicat als valors de les fulles |
Fixa't en l'última fila: la regularització de 07-01 reapareix dins dels arbres. Les tècniques d'aquest mòdul no són compartiments estancs, són peces combinables. La recepta defensiva estàndard: learning rate baix + early stopping + arbres poc profunds, i validar sempre amb la CV del mòdul 6.
Interpretació: feature importance i SHAP
Com el Random Forest, els models de boosting ofereixen feature_importances_ (a sklearn clàssic i a XGBoost/LightGBM) amb les mateixes virtuts i els mateixos biaixos que vam discutir a 07-02: útils com a rànquing global, perilloses amb features correlacionades.
Per a explicacions serioses, l'estàndard actual és SHAP (SHapley Additive exPlanations, biblioteca shap): assigna a cada feature de cada predicció individual una contribució amb signe — "a aquest client el model li dona un 78% de churn: la recència de 45 dies aporta +0.20, les seves 2 incidències +0.12 i la seva antiguitat de 5 anys −0.08". Això és or per a l'equip de retenció de MercaFresh, que necessita saber no només qui se'n va sinó per què. No ho desenvolupem aquí — és matèria d'interpretabilitat avançada i reapareixerà en el context ètic de 08-04 —, però convé que sàpigues que existeix i que es porta especialment bé amb els models d'arbres.
Errors Comuns i Consells
- Apujar
n_estimators"perquè més és millor". Cert a Random Forest, fals en boosting: aquí cada arbre extra afegeix complexitat. Fixa un sostre alt i deixa que l'early stopping decideixi. - Ajustar el learning rate sense tocar el nombre d'arbres. Van acoblats: si abaixes η de 0.1 a 0.01, multiplica el pressupost d'arbres per ~10 o el model quedarà infraentrenat.
- Usar arbres profunds com a base.
max_depth=10en boosting sol ser una recepta de sobreajustament; la força és a la seqüència de correctors febles, no en correctors forts. - Fer early stopping contra el conjunt de prova. El conjunt que decideix quan parar participa en l'entrenament a tots els efectes: és una fuita de les de 06-01. Usa una partició de validació o la validació interna del mateix algorisme, i reserva la prova intacta.
- Escalar les features "per si de cas". No fa mal, però és innecessari: com tots els mètodes d'arbres, el boosting és insensible a l'escala. Estalvia't aquest pas del pipeline (i recorda que sí que és obligatori per a SVM, K-NN o els models regularitzats de 07-01).
- Consell: en projectes reals, entrena primer un Random Forest (baseline forta, 07-02) i després un HistGradientBoosting/LightGBM amb early stopping. Si el boosting no supera clarament el bosc, queda't amb el bosc: menys hiperparàmetres per mantenir.
Exercicis
- Boosting a mà, quarta iteració. Repeteix l'exemple numèric de la lliçó però amb learning rate η = 0.5: recalcula prediccions i residus de les iteracions 1 i 2 i afegeix-hi una iteració 3 (assumeix que cada arbre continua predint la mitjana del residu del seu grup, alternant la divisió per freqüència i la que separa dins de cada grup). S'arriba a residu zero? Què il·lustra això sobre η?
- L'acoblament η–n_estimators. Sobre el churn de MercaFresh, entrena
GradientBoostingClassifier(max_depth=3, subsample=0.8)amb les combinacions (η=0.3, 50 arbres), (η=0.1, 150), (η=0.03, 500) i (η=0.3, 500). Avalua l'F1 amb la CV estratificada. Confirmen els resultats la taula de la secció 3? - Corba d'early stopping. Amb
train_test_split(estratificat) separa un 20% de validació del churn. EntrenaGradientBoostingClassifier(n_estimators=400, learning_rate=0.1, max_depth=3)i usastaged_predict_probaper calcular la log-loss en entrenament i en validació després de cada arbre. Dibuixa totes dues corbes: en quina iteració hauria parat un early stopping amb paciència 20? Quina forma de 06-05 hi reconeixes?
Solucions
- Amb η = 0.5, la iteració 1 suma la meitat de la correcció: prediccions 95/95/65/65 i residus +25/+5/−25/−5. La iteració 2 (correcció per grups de freqüència: mitjana de residus ±15, aplicada al 50%) deixa prediccions 102.5/102.5/57.5/57.5 i residus +17.5/−2.5/−17.5/+2.5; la iteració 3 continua reduint però no arriba a zero. Il·lustració: amb η < 1 el model s'aproxima asimptòticament a l'ajust perfecte en entrenament — no el clava mai de cop —, i això dona marge per aturar la seqüència (early stopping) en el punt de millor generalització abans de memoritzar el soroll.
- Les tres primeres combinacions (pressupost equilibrat η·n_estimators ≈ 15) donen F1 semblants, amb un lleuger avantatge habitual per a η baix + molts arbres i menys desviació entre folds. La quarta (η=0.3 amb 500 arbres, pressupost 150) rendeix pitjor en validació tot i ser la que té menys error d'entrenament: overfitting pur. Confirma la taula: el que importa és el producte equilibrat, i passar-se de pressupost passa factura.
- La log-loss d'entrenament descendeix monòtonament (el boosting sempre pot continuar llimant residus). La de validació baixa, toca mínim — típicament entre les iteracions 80 i 200 amb aquestes dades — i després ascendeix suaument: la silueta clàssica de la corba de validació de 06-05, ara amb "nombre d'arbres" a l'eix x. L'early stopping amb paciència 20 hauria tallat unes 20 iteracions després del mínim, quedant-se amb el model de la millor iteració. Aquest exercici és exactament el que
early_stopping=Trueautomatitza per dins.
Conclusió
El gradient boosting materialitza la promesa del boosting: una predicció inicial trivial més una cadena d'arbres nans, cadascun entrenat sobre els residus del conjunt anterior, amb el learning rate encongint cada pas — descens de gradient en l'espai de les prediccions. Has vist els seus dos controls acoblats (η i n_estimators), les seves implementacions per ordre de modernitat (clàssica de sklearn, HistGradientBoosting, XGBoost i LightGBM), el seu duel amb Random Forest sobre el churn de MercaFresh i, sobretot, el seu caràcter: l'algorisme més potent en dades tabulars és també el més propens a memoritzar, i per això viatja envoltat de frens — learning rate baix, early stopping, arbres petits, submostreig i la regularització de 07-01 aplicada a les seves fulles. Amb arbres i ensembles hem arribat molt lluny partint de models senzills; la lliçó següent explora l'altra gran via cap a la potència: apilar capes de neurones fins a construir xarxes profundes, el deep learning que l'MLP de 04-07 va deixar anunciat.
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
