XGBoost vs LightGBM nel 2026: Gradient Boosting e Domande per Colloqui di Data Science

Confronto completo tra XGBoost e LightGBM: tuning degli iperparametri, gestione delle feature categoriche e domande frequenti nei colloqui di data science con esempi Python.

XGBoost vs LightGBM nel 2026: Gradient Boosting e Domande per Colloqui di Data Science

XGBoost e LightGBM rimangono nel 2026 le implementazioni di gradient boosting più performanti per i dati tabulari. Entrambe le librerie superano costantemente il deep learning sui dataset strutturati, specialmente quando il numero di campioni di training è limitato. Con XGBoost 2.1 e LightGBM 4.5, l'accelerazione GPU e la gestione delle feature categoriche sono state ulteriormente migliorate.

Suggerimento per il Colloquio

Alla domanda "Perché usare XGBoost invece di una rete neurale?", è importante sottolineare che il gradient boosting gestisce i dati tabulari con meno campioni in modo più efficace, richiede meno feature engineering e fornisce l'importanza delle feature integrata. Le reti neurali eccellono con dati non strutturati come immagini, testo o audio, ma hanno difficoltà con feature tabulari eterogenee.

Differenze tra Gradient Boosting e Random Forests

Gradient boosting e Random Forests utilizzano entrambi alberi decisionali, ma l'approccio al training differisce fondamentalmente. Random Forests addestra alberi in modo indipendente e parallelo, poi calcola la media delle previsioni. Il gradient boosting addestra alberi in sequenza, con ogni albero che corregge gli errori dell'ensemble precedente.

La formulazione matematica chiarisce questa distinzione. All'iterazione m, il gradient boosting adatta un nuovo albero h_m(x) al gradiente negativo della funzione di perdita rispetto alle previsioni dell'ensemble corrente. Per la perdita quadratica, questo gradiente negativo equivale ai residui.

python
# gradient_boosting_demo.py
import numpy as np
from sklearn.tree import DecisionTreeRegressor

def gradient_boosting_from_scratch(X, y, n_estimators=100, learning_rate=0.1, max_depth=3):
    """Simplified gradient boosting for regression to illustrate the algorithm."""
    # Initialize predictions with the mean (minimizes squared error)
    predictions = np.full(len(y), y.mean())
    trees = []
    
    for _ in range(n_estimators):
        # Compute negative gradient (residuals for MSE loss)
        residuals = y - predictions
        
        # Fit a tree to the residuals
        tree = DecisionTreeRegressor(max_depth=max_depth)
        tree.fit(X, residuals)
        trees.append(tree)
        
        # Update predictions with shrinkage (learning rate)
        predictions += learning_rate * tree.predict(X)
    
    return trees, y.mean()

Questa dipendenza sequenziale rende il gradient boosting più lento nel training rispetto a Random Forests, ma tipicamente più accurato sullo stesso dataset.

Architettura XGBoost e Parametri Chiave

XGBoost (eXtreme Gradient Boosting) ha introdotto diverse ottimizzazioni che hanno reso il gradient boosting praticabile su larga scala. La libreria utilizza una funzione obiettivo regolarizzata che combina la perdita con penalità L1 e L2 sui pesi delle foglie, riducendo l'overfitting senza una validazione incrociata estensiva.

python
# xgboost_classification.py
import xgboost as xgb
from sklearn.datasets import make_classification
from sklearn.model_selection import train_test_split

# Generate synthetic classification data
X, y = make_classification(n_samples=10000, n_features=20, n_informative=10, random_state=42)
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)

# XGBoost with commonly tuned hyperparameters
model = xgb.XGBClassifier(
    n_estimators=500,           # Number of boosting rounds
    max_depth=6,                # Maximum tree depth (controls complexity)
    learning_rate=0.1,          # Shrinkage factor (eta in XGBoost docs)
    subsample=0.8,              # Row sampling ratio per tree
    colsample_bytree=0.8,       # Column sampling ratio per tree
    reg_alpha=0.1,              # L1 regularization on leaf weights
    reg_lambda=1.0,             # L2 regularization on leaf weights
    tree_method='hist',         # Histogram-based algorithm (faster)
    early_stopping_rounds=50,   # Stop if no improvement after 50 rounds
    random_state=42
)

model.fit(
    X_train, y_train,
    eval_set=[(X_test, y_test)],  # Validation set for early stopping
    verbose=False
)

print(f"Best iteration: {model.best_iteration}")
print(f"Test accuracy: {model.score(X_test, y_test):.4f}")

Il parametro tree_method='hist' merita particolare attenzione. La costruzione degli alberi basata su istogrammi quantizza le feature continue in bin discreti, riducendo l'utilizzo della memoria e accelerando la ricerca degli split. XGBoost 2.0+ utilizza questo metodo come predefinito.

LightGBM: Crescita Leaf-Wise e Gestione Categorica

LightGBM (Light Gradient Boosting Machine) di Microsoft ha introdotto due innovazioni che spesso lo rendono più veloce di XGBoost: la crescita degli alberi leaf-wise e il Gradient-based One-Side Sampling (GOSS).

Gli alberi decisionali tradizionali crescono level-wise, dividendo tutti i nodi a una data profondità prima di procedere più in profondità. LightGBM cresce leaf-wise, dividendo sempre la foglia con il guadagno potenziale più alto. Questo approccio asimmetrico produce alberi più complessi con meno split, raggiungendo spesso una perdita di training inferiore più rapidamente.

python
# lightgbm_with_categorical.py
import lightgbm as lgb
import pandas as pd
import numpy as np
from sklearn.model_selection import train_test_split

# Create dataset with categorical features
np.random.seed(42)
df = pd.DataFrame({
    'category_a': np.random.choice(['low', 'medium', 'high'], 10000),
    'category_b': np.random.choice(['type1', 'type2', 'type3', 'type4'], 10000),
    'numeric_1': np.random.randn(10000),
    'numeric_2': np.random.randn(10000),
    'target': np.random.randint(0, 2, 10000)
})

# Convert to categorical dtype (LightGBM reads this automatically)
df['category_a'] = df['category_a'].astype('category')
df['category_b'] = df['category_b'].astype('category')

X = df.drop('target', axis=1)
y = df['target']
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)

# LightGBM handles categorical features natively
model = lgb.LGBMClassifier(
    n_estimators=500,
    max_depth=-1,               # No limit (leaf-wise growth controls complexity)
    num_leaves=31,              # Maximum leaves per tree (key LightGBM param)
    learning_rate=0.1,
    subsample=0.8,
    colsample_bytree=0.8,
    min_child_samples=20,       # Minimum samples in a leaf
    reg_alpha=0.1,
    reg_lambda=1.0,
    random_state=42,
    verbose=-1
)

model.fit(
    X_train, y_train,
    eval_set=[(X_test, y_test)],
    callbacks=[lgb.early_stopping(50, verbose=False)]
)

print(f"Best iteration: {model.best_iteration_}")
print(f"Test accuracy: {model.score(X_test, y_test):.4f}")

La gestione nativa delle feature categoriche di LightGBM supera il one-hot encoding per feature ad alta cardinalità. L'algoritmo trova split ottimali tra i valori categorici senza creare matrici sparse.

Pronto a superare i tuoi colloqui su Data Science & ML?

Pratica con i nostri simulatori interattivi, flashcards e test tecnici.

XGBoost vs LightGBM: Confronto Pratico

La scelta tra XGBoost e LightGBM dipende dalle caratteristiche del dataset e dai vincoli. Ecco un confronto diretto basato su benchmark ed esperienza pratica:

AspettoXGBoost 2.1LightGBM 4.5
Velocità di trainingPiù lento su dataset grandi2-5x più veloce con GOSS
Utilizzo memoriaPiù altoPiù basso (histogram binning)
Feature categoricheRichiede encodingSupporto nativo
Crescita alberoLevel-wise (default)Leaf-wise
Supporto GPUCUDA, metodo histogramCUDA, supporto nativo
Rischio overfittingPiù basso (level-wise)Più alto (leaf-wise, regolare num_leaves)
Dataset piccoli (<10k righe)Spesso miglioreComparabile
Dataset grandi (>1M righe)Più lentoPreferito

Per attività di feature engineering dove il tempo di training è importante, il vantaggio di velocità di LightGBM diventa significativo durante la sperimentazione iterativa.

Strategia di Tuning degli Iperparametri per i Colloqui

Gli intervistatori chiedono frequentemente come ottimizzare i modelli di gradient boosting. Un approccio strutturato dimostra pensiero sistematico invece di una ricerca grid casuale.

python
# hyperparameter_tuning.py
import optuna
import xgboost as xgb
from sklearn.model_selection import cross_val_score
from sklearn.datasets import make_classification

X, y = make_classification(n_samples=5000, n_features=20, n_informative=10, random_state=42)

def objective(trial):
    """Optuna objective for XGBoost hyperparameter optimization."""
    params = {
        # Start with learning rate and n_estimators
        'learning_rate': trial.suggest_float('learning_rate', 0.01, 0.3, log=True),
        'n_estimators': trial.suggest_int('n_estimators', 100, 1000),
        
        # Tree complexity (most important for bias-variance tradeoff)
        'max_depth': trial.suggest_int('max_depth', 3, 10),
        'min_child_weight': trial.suggest_int('min_child_weight', 1, 10),
        
        # Regularization (reduce overfitting)
        'reg_alpha': trial.suggest_float('reg_alpha', 1e-8, 10.0, log=True),
        'reg_lambda': trial.suggest_float('reg_lambda', 1e-8, 10.0, log=True),
        
        # Sampling (stochastic gradient boosting)
        'subsample': trial.suggest_float('subsample', 0.5, 1.0),
        'colsample_bytree': trial.suggest_float('colsample_bytree', 0.5, 1.0),
        
        'tree_method': 'hist',
        'random_state': 42
    }
    
    model = xgb.XGBClassifier(**params)
    scores = cross_val_score(model, X, y, cv=5, scoring='roc_auc')
    return scores.mean()

study = optuna.create_study(direction='maximize')
study.optimize(objective, n_trials=50, show_progress_bar=True)

print(f"Best ROC-AUC: {study.best_value:.4f}")
print(f"Best params: {study.best_params}")

L'ordine di priorità del tuning è importante: prima learning rate e numero di estimatori, poi complessità dell'albero (max_depth, num_leaves), poi regolarizzazione, infine rapporti di sampling. Questo riflette come i parametri influenzano il tradeoff bias-varianza.

Domande Comuni nei Colloqui sul Gradient Boosting

I colloqui di data science testano sia la comprensione teorica che le capacità pratiche di debugging. Queste domande appaiono frequentemente nei colloqui presso aziende che lavorano con dati tabulari.

D: Perché il gradient boosting tende all'overfitting più facilmente di Random Forests?

Il gradient boosting addestra in sequenza, con ogni albero che adatta esplicitamente gli errori dell'ensemble. Gli alberi tardivi possono memorizzare il rumore nei residui. Random Forests addestra alberi indipendentemente su campioni bootstrap, e la media riduce la varianza. La regolarizzazione (learning rate, subsampling, vincoli sugli alberi) mitiga questo nel gradient boosting.

D: Cosa causa risultati diversi di XGBoost sugli stessi dati?

Il non-determinismo deriva da tre fonti: row subsampling (subsample), column subsampling (colsample_bytree) e costruzione parallela degli istogrammi. Impostare random_state fissa le prime due. Per riproducibilità esatta, impostare anche n_jobs=1, sebbene questo rallenti il training.

D: Come si gestisce lo sbilanciamento delle classi in XGBoost?

Tre approcci funzionano:

  1. scale_pos_weight: Impostare a (negative_count / positive_count) per classificazione binaria
  2. sample_weight: Passare pesi delle istanze a fit()
  3. Resampling: SMOTE o random undersampling prima del training

L'approccio scale_pos_weight modifica la funzione di perdita e preserva la distribuzione originale dei dati, spesso preferito al resampling.

D: Quando scegliere CatBoost invece di XGBoost o LightGBM?

CatBoost eccelle quando il dataset contiene molte feature categoriche ad alta cardinalità e quando ridurre l'overfitting con tuning minimo è una priorità. L'ordered boosting e la struttura ad albero simmetrica lo rendono più resistente all'overfitting su dataset piccoli. Il compromesso è un training più lento rispetto a LightGBM.

Per i fondamenti della classificazione, consultare il modulo di apprendimento supervisionato per la classificazione.

Feature Importance e Interpretabilità del Modello

Spiegare le previsioni è importante nei settori regolamentati e costruisce fiducia con gli stakeholder. Sia XGBoost che LightGBM forniscono feature importance integrata, ma l'interpretazione richiede attenzione.

python
# feature_importance.py
import xgboost as xgb
import matplotlib.pyplot as plt
from sklearn.datasets import make_classification

X, y = make_classification(n_samples=5000, n_features=20, n_informative=10, random_state=42)
feature_names = [f'feature_{i}' for i in range(20)]

model = xgb.XGBClassifier(n_estimators=100, random_state=42)
model.fit(X, y)

# Three importance types available
importance_types = ['weight', 'gain', 'cover']

for imp_type in importance_types:
    importance = model.get_booster().get_score(importance_type=imp_type)
    print(f"\n{imp_type.upper()} importance (top 5):")
    sorted_imp = sorted(importance.items(), key=lambda x: x[1], reverse=True)[:5]
    for feat, score in sorted_imp:
        print(f"  {feat}: {score:.2f}")
  • Weight: Numero di volte che una feature appare negli split in tutti gli alberi
  • Gain: Miglioramento medio nella funzione obiettivo quando la feature è usata per lo split
  • Cover: Numero medio di campioni influenzati dagli split su questa feature

Il gain tipicamente fornisce la misura di importance più significativa, poiché si relaziona direttamente al miglioramento del modello. Tuttavia, feature correlate possono avere importance sottostimata poiché il modello potrebbe dividere su una delle due.

Per l'interpretazione causale, i valori SHAP (disponibili tramite la libreria shap) forniscono attribuzioni delle feature consistenti e teoricamente fondate per ogni previsione.

Considerazioni per il Deploy in Produzione

Il deploy di modelli gradient boosting introduce problemi di latenza e serializzazione che differiscono dal training.

python
# model_serialization.py
import xgboost as xgb
import json

# Train a model
model = xgb.XGBClassifier(n_estimators=100, random_state=42)
model.fit(X_train, y_train)

# Save in XGBoost's native binary format (recommended for production)
model.save_model('model.ubj')  # Universal Binary JSON format

# Load for inference
loaded_model = xgb.XGBClassifier()
loaded_model.load_model('model.ubj')

# For model versioning, save with metadata
metadata = {
    'version': '1.0.0',
    'trained_at': '2026-09-17',
    'features': feature_names,
    'best_iteration': model.best_iteration
}
with open('model_metadata.json', 'w') as f:
    json.dump(metadata, f)

La latenza di inferenza dipende dalla profondità e dal numero degli alberi. Per applicazioni real-time con requisiti di latenza stringenti (sotto 10ms), considerare:

  • Ridurre n_estimators con un learning rate più alto
  • Limitare max_depth a 4-5
  • Usare il metodo predict() con iteration_range per usare meno alberi

Punti Chiave per Colloqui su XGBoost e LightGBM

  • Il gradient boosting addestra alberi sequenzialmente sui residui, a differenza di Random Forests che addestra in parallelo e calcola la media
  • XGBoost aggiunge regolarizzazione L1/L2 alla funzione obiettivo, riducendo l'overfitting senza validazione incrociata estensiva
  • LightGBM usa crescita leaf-wise e sampling GOSS, rendendolo 2-5x più veloce su dataset grandi
  • La gestione nativa categorica in LightGBM supera il one-hot encoding per feature ad alta cardinalità
  • Ordine di tuning: learning rate, complessità dell'albero, regolarizzazione, rapporti di sampling
  • scale_pos_weight gestisce lo sbilanciamento delle classi modificando la funzione di perdita, preservando la distribuzione originale
  • La feature importance basata sul gain misura il miglioramento effettivo del modello, ma feature correlate possono apparire meno importanti
  • Per la produzione, usare il formato .ubj e considerare di ridurre il numero di alberi per applicazioni sensibili alla latenza

Inizia a praticare!

Metti alla prova le tue conoscenze con i nostri simulatori di colloquio e test tecnici.

Sfida del giorno

Sapresti trovare il bug in Data Science & ML?

Uno snippet reale, un bug nascosto, un tentativo al giorno. Senza account per provare.

Anthony Fillion-Maillet

Scritto da

Anthony Fillion-Maillet

Fondatore di SharpSkill

Sviluppatore fullstack da oltre 10 anni. Guida SharpSkill e risponde di tutto ciò che vi viene pubblicato.

Aggiornato il 17 settembre 2026

Condividi

Articoli correlati