Machine Learning: Aprendizado por Ensemble
Última atualização: 2026-08-26
Três sapateiros com seus engenhos combinados igualam o mestre Zhuge Liang — o Boosting encadeia aprendizes fracos para torná-los fortes, e XGBoost/LightGBM são as versões industriais e turbinadas.
1. O que você vai aprender
- Fundamentos de Boosting: o caminho evolutivo de AdaBoost → Gradient Boosting → XGBoost/LightGBM
- XGBoost: função objetivo regularizada, amostragem de colunas, divisão por quantis aproximados, aceleração por GPU
- LightGBM: inovações GOSS/EFB, divisão baseada em histogramas, suporte nativo a features categóricas, vantagens de velocidade de treino
- Ajuste de hiperparâmetros: learning_rate/n_estimators/max_depth/num_leaves/reg_alpha/reg_lambda
- A escolha do modelo principal do Bob: uma comparação de desempenho XGBoost vs. LightGBM nos dados do SalesPredict
2. A história real de um engenheiro de algoritmos
(1) O problema: Random Forest é lento demais em dados na escala de milhões
Os dados do SalesPredict do Bob cresceram para 1 milhão de linhas, e treinar um Random Forest com 100 árvores leva 45 minutos. Com 10 experimentos para rodar por dia, apenas esperar pelo treinamento consome 7,5 horas. Os dados dos EUA da Alice, com 2 milhões de linhas, são ainda mais lentos. A velocidade de treinamento limita a eficiência de experimentação e indiretamente desacelera a iteração do modelo.
(2) A solução com XGBoost/LightGBM
Através de otimizações como divisão baseada em histogramas e amostragem de colunas, XGBoost e LightGBM reduzem o tempo de treinamento em 5-10x enquanto entregam precisão ainda maior.
import xgboost as xgb
import lightgbm as lgb
from sklearn.model_selection import cross_val_score
from sklearn.metrics import r2_score
# XGBoost
xgb_model = xgb.XGBRegressor(
n_estimators=200,
max_depth=6,
learning_rate=0.1,
random_state=42,
tree_method="hist", # Histograma para velocidade
)
xgb_model.fit(X_train, y_train)
print(f"XGBoost R²: {xgb_model.score(X_test, y_test):.4f}")
# LightGBM (geralmente 2-3x mais rápido que XGBoost)
lgb_model = lgb.LGBMRegressor(
n_estimators=200,
num_leaves=31,
learning_rate=0.1,
random_state=42,
)
lgb_model.fit(X_train, y_train)
print(f"LightGBM R²: {lgb_model.score(X_test, y_test):.4f}")
(3) O resultado: 10x mais rápido, 5% mais preciso
A velocidade de treinamento passou de 45 minutos para 5 minutos, e o R² melhorou de 0,82 (Random Forest) para 0,86 (LightGBM). O Bob agora consegue rodar 20 experimentos por dia, acelerando a iteração do modelo em 4x.
3. A Família Boosting
(1) AdaBoost → Gradient Boosting → XGBoost/LightGBM
graph LR
A[AdaBoost<br/>1995] --> B[Gradient Boosting<br/>1999]
B --> C[XGBoost<br/>2014]
B --> D[LightGBM<br/>2017]
C --> E[CatBoost<br/>2018]
style A fill:#FFD700
style B fill:#90EE90
style C fill:#87CEEB
style D fill:#FFB6C1
| Algoritmo | Inovação central | Velocidade | Precisão | Suporte categórico |
|---|---|---|---|---|
| AdaBoost | Reweight samples | Lenta | Média | Não |
| Gradient Boosting | Ajustar aos resíduos | Lenta | Alta | Não |
| XGBoost | Função objetivo regularizada + histograma | Rápida | Muito alta | Não (requer encoding) |
| LightGBM | GOSS + EFB + histograma | Muito rápida | Muito alta | Sim (nativo) |
▶ Exemplo: Comparação AdaBoost vs. XGBoost
from sklearn.ensemble import AdaBoostRegressor
from sklearn.tree import DecisionTreeRegressor
import xgboost as xgb
from sklearn.model_selection import cross_val_score
from sklearn.datasets import make_regression
import numpy as np
X, y = make_regression(n_samples=1000, n_features=20, random_state=42)
# AdaBoost (mais lento, menos preciso)
ada = AdaBoostRegressor(
estimator=DecisionTreeRegressor(max_depth=3),
n_estimators=100,
random_state=42,
)
ada_scores = cross_val_score(ada, X, y, cv=3, scoring="r2")
# XGBoost (mais rápido, mais preciso)
xgb_model = xgb.XGBRegressor(n_estimators=100, max_depth=6, random_state=42)
xgb_scores = cross_val_score(xgb_model, X, y, cv=3, scoring="r2")
print(f"AdaBoost R²: {ada_scores.mean():.4f}")
print(f"XGBoost R²: {xgb_scores.mean():.4f}")
Saída:
# Executado com sucesso
4. XGBoost em Profundidade
(1) Função Objetivo Regularizada
graph TB
OBJ[Função Objetivo] --> LOSS[Perda Empírica<br/>∑ L(yi, ŷi)]
OBJ --> REG[Termo de Regularização<br/>Ω f = γT + ½λ∑w²]
LOSS --> GRAD[Gradiente<br/>gi = ∂L/∂ŷi]
LOSS --> HESS[Hessiana<br/>hi = ∂²L/∂ŷi²]
GRAD --> SPLIT[Melhor Divisão<br/>Gain = ½[GL²/(HL+λ) + GR²/(HR+λ) - (GL+GR)²/(HL+HR+λ)] - γ]
HESS --> SPLIT
▶ Exemplo: XGBoost com ajuste de hiperparâmetros
import xgboost as xgb
from sklearn.model_selection import train_test_split, cross_val_score
from sklearn.metrics import mean_absolute_error, r2_score
import numpy as np
rng = np.random.default_rng(42)
n = 5000
X = rng.standard_normal((n, 8))
y = 50 + 0.8 * X[:, 0] + 1.5 * X[:, 1] - 0.6 * X[:, 2] + rng.normal(0, 5, n)
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)
# XGBoost com tree_method="hist" para velocidade
model = xgb.XGBRegressor(
n_estimators=200,
max_depth=6,
learning_rate=0.1,
subsample=0.8,
colsample_bytree=0.8,
reg_alpha=0.1,
reg_lambda=1.0,
random_state=42,
tree_method="hist",
n_jobs=-1,
)
model.fit(X_train, y_train, eval_set=[(X_test, y_test)], verbose=False)
y_pred = model.predict(X_test)
print(f"XGBoost R²: {r2_score(y_test, y_pred):.4f}")
print(f"XGBoost MAE: {mean_absolute_error(y_test, y_pred):.2f}")
Saída:
# Executado com sucesso
(2) Early Stopping
▶ Exemplo: Evitar sobreajuste com early stopping
import xgboost as xgb
from sklearn.model_selection import train_test_split
import numpy as np
rng = np.random.default_rng(42)
X = rng.standard_normal((1000, 8))
y = 50 + 0.8 * X[:, 0] + rng.normal(0, 5, 1000)
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)
# Dividir treino em treino + validação para early stopping
X_tr, X_val, y_tr, y_val = train_test_split(X_train, y_train, test_size=0.2, random_state=42)
model = xgb.XGBRegressor(
n_estimators=1000,
learning_rate=0.05,
max_depth=6,
early_stopping_rounds=20, # Parar se 20 rodadas sem melhora
random_state=42,
)
model.fit(X_tr, y_tr, eval_set=[(X_val, y_val)], verbose=False)
print(f"Melhor iteração: {model.best_iteration}")
print(f"Melhor score: {model.best_score:.4f}")
Saída:
# Executado com sucesso
5. LightGBM — O Mais Rápido
(1) GOSS e EFB
graph TB
LGB[LightGBM] --> GOSS[GOSS<br/>Gradient-based One-Side Sampling]
LGB --> EFB[EFB<br/>Exclusive Feature Bundling]
GOSS --> SPEED[10x mais rápido que XGBoost]
EFB --> SPEED
GOSS --> KEEP[Manter amostras com gradiente alto]
GOSS --> DROP[Descartar amostras com gradiente baixo<br/>com reponderação]
EFB --> BUNDLE[Agrupar features mutuamente exclusivas<br/>reduzir dimensionalidade]
▶ Exemplo: LightGBM em dados de larga escala
import lightgbm as lgb
from sklearn.model_selection import train_test_split
from sklearn.metrics import mean_absolute_error, r2_score
import numpy as np
import time
rng = np.random.default_rng(42)
n = 100000 # Dados na escala de 100k
X = rng.standard_normal((n, 20))
y = 50 + 0.8 * X[:, 0] + 1.5 * X[:, 1] + rng.normal(0, 5, n)
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)
# LightGBM com feature_fraction + bagging
start = time.time()
model = lgb.LGBMRegressor(
n_estimators=200,
num_leaves=31,
learning_rate=0.1,
feature_fraction=0.8,
bagging_fraction=0.8,
bagging_freq=5,
random_state=42,
n_jobs=-1,
verbose=-1,
)
model.fit(X_train, y_train)
elapsed = time.time() - start
y_pred = model.predict(X_test)
print(f"LightGBM R²: {r2_score(y_test, y_pred):.4f}")
print(f"LightGBM MAE: {mean_absolute_error(y_test, y_pred):.2f}")
print(f"Tempo de treino: {elapsed:.1f}s")
Saída:
# Executado com sucesso
(2) Suporte Nativo a Features Categóricas
▶ Exemplo: LightGBM com features categóricas
import lightgbm as lgb
import pandas as pd
import numpy as np
rng = np.random.default_rng(42)
n = 2000
df = pd.DataFrame({
"city": rng.choice(["SP", "RJ", "MG", "RS", "BA"], n),
"category": rng.choice(["Eletrônicos", "Roupas", "Alimentos"], n),
"price": rng.uniform(10, 1000, n),
"stock": rng.integers(1, 100, n),
})
df["sales"] = 100 + df["price"] * 0.5 + rng.normal(0, 20, n)
# LightGBM aceita categorias nativamente — sem necessidade de encoding
X = df[["city", "category", "price", "stock"]]
y = df["sales"]
model = lgb.LGBMRegressor(n_estimators=100, num_leaves=31, verbose=-1)
model.fit(X, y, categorical_feature=["city", "category"])
print(f"R²: {model.score(X, y):.4f}")
Saída:
# Executado com sucesso
6. Ajuste de Hiperparâmetros
(1) Tabela de Parâmetros-Chave
| Parâmetro | XGBoost | LightGBM | Efeito |
|---|---|---|---|
| Número de árvores | n_estimators | n_estimators | Mais = mais forte, mas mais lento |
| Profundidade máxima | max_depth | num_leaves | Maior = mais complexo (padrão: 6/XGB, 31/LGB) |
| Learning rate | learning_rate | learning_rate | Menor = mais robusto, mais árvores necessárias |
| Regularização L1 | reg_alpha | reg_alpha | Encolhe coeficientes, seleção de features |
| Regularização L2 | reg_lambda | reg_lambda | Encolhe pesos, antissobreajuste |
| Subamostragem | subsample | bagging_fraction | Reduz variância |
| Subamostragem de colunas | colsample_bytree | feature_fraction | Reduz correlação entre árvores |
| Mínimo de amostras por folha | min_child_weight | min_data_in_leaf | Evita sobreajuste |
(2) Exemplo: Comparação XGBoost vs. LightGBM no SalesPredict
import xgboost as xgb
import lightgbm as lgb
from sklearn.model_selection import cross_val_score, train_test_split
from sklearn.metrics import r2_score
import pandas as pd
import numpy as np
import time
rng = np.random.default_rng(42)
n = 5000
df = pd.DataFrame({
"ad_spend": rng.uniform(10, 100, n),
"traffic": rng.uniform(100, 1000, n),
"category": rng.choice(["Eletrônicos", "Roupas", "Alimentos", "Casa"], n),
"is_promotion": rng.choice([0, 1], n),
"customer_count": rng.integers(50, 500, n),
})
df["revenue"] = (
20 + 0.6 * df["ad_spend"] + 0.08 * df["traffic"]
+ 0.5 * df["customer_count"] + 50 * df["is_promotion"]
+ rng.normal(0, 15, n)
)
X = df.drop(columns=["revenue"])
y = df["revenue"]
# XGBoost
start = time.time()
xgb_scores = cross_val_score(
xgb.XGBRegressor(n_estimators=200, max_depth=6, learning_rate=0.1, random_state=42),
X, y, cv=5, scoring="r2"
)
xgb_time = time.time() - start
# LightGBM
start = time.time()
lgb_scores = cross_val_score(
lgb.LGBMRegressor(n_estimators=200, num_leaves=31, learning_rate=0.1, random_state=42, verbose=-1),
X, y, cv=5, scoring="r2"
)
lgb_time = time.time() - start
print(f"XGBoost: R²={xgb_scores.mean():.4f}, tempo={xgb_time:.1f}s")
print(f"LightGBM: R²={lgb_scores.mean():.4f}, tempo={lgb_time:.1f}s")
Saída:
# Executado com sucesso
7. Modelo Principal do Bob: Pipeline Completo do SalesPredict
▶ Exemplo: Construindo o modelo de produção
import lightgbm as lgb
from sklearn.model_selection import train_test_split, cross_val_score
from sklearn.metrics import mean_absolute_error, r2_score
from sklearn.preprocessing import StandardScaler
from sklearn.pipeline import Pipeline
import pandas as pd
import numpy as np
# Dados do SalesPredict
rng = np.random.default_rng(42)
n = 10000
df = pd.DataFrame({
"ad_spend_k": rng.uniform(5, 100, n),
"traffic_k": rng.uniform(10, 500, n),
"category": rng.choice(["Eletrônicos", "Roupas", "Alimentos", "Casa", "Beleza"], n),
"is_promotion": rng.choice([0, 1], n, p=[0.8, 0.2]),
"is_weekend": rng.choice([0, 1], n, p=[0.7, 0.3]),
"customer_count": rng.integers(50, 500, n),
"month": rng.integers(1, 13, n),
})
df["revenue_k"] = (
20 + 0.6 * df["ad_spend_k"] + 0.08 * df["traffic_k"]
+ 0.5 * df["customer_count"] + 50 * df["is_promotion"]
+ 10 * df["is_weekend"] + 5 * np.sin(2 * np.pi * df["month"] / 12)
+ rng.normal(0, 12, n)
)
X = df.drop(columns=["revenue_k"])
y = df["revenue_k"]
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)
# Modelo principal: LightGBM com features categóricas nativas
model = lgb.LGBMRegressor(
n_estimators=500,
num_leaves=63,
learning_rate=0.05,
feature_fraction=0.8,
bagging_fraction=0.8,
bagging_freq=5,
min_data_in_leaf=20,
reg_alpha=0.1,
reg_lambda=1.0,
random_state=42,
verbose=-1,
)
model.fit(
X_train, y_train,
categorical_feature=["category"],
eval_set=[(X_test, y_test)],
callbacks=[lgb.early_stopping(20, verbose=False)],
)
y_pred = model.predict(X_test)
print(f"Modelo principal R²: {r2_score(y_test, y_pred):.4f}")
print(f"Modelo principal MAE: {mean_absolute_error(y_test, y_pred):.2f} mil USD")
print(f"Melhor iteração: {model.best_iteration_}")
Saída:
# Executado com sucesso
❓ Perguntas Frequentes
P: XGBoost ou LightGBM, qual escolher? R: Na maioria dos casos, os dois são equivalentes em precisão. LightGBM é mais rápido em grandes conjuntos de dados (>100k linhas) e suporta features categóricas nativamente. XGBoost tem melhor suporte de GPU e é mais maduro. Comece com LightGBM e mude para XGBoost se encontrar problemas específicos.
P: Como evitar o sobreajuste em XGBoost/LightGBM? R: Três ferramentas — 1) Regularização L1/L2 (reg_alpha/reg_lambda); 2) Subamostragem (subsample<1, colsample_bytree<1); 3) Early stopping (parar quando a perda de validação para de melhorar).
P: Qual é o valor inicial de learning_rate? R: 0,05–0,1 é o intervalo padrão. Menor (0,01–0,05) geralmente dá melhor precisão final mas requer mais árvores (e mais tempo de treino). 0,1 é adequado para prototipagem rápida.
P: Qual a diferença entre max_depth (XGBoost) e num_leaves (LightGBM)? R: max_depth limita a profundidade da árvore; num_leaves limita o número de nós folha. LightGBM cresce a árvore leaf-wise (por folha), então num_leaves afeta o controle de complexidade de forma diferente. Regra prática: num_leaves = 2^max_depth - 1.
P: Quando usar early stopping? R: Sempre que tiver dados de validação. Defina eval_set no fit e early_stopping_rounds=20-50. Sem early stopping, o modelo facilmente sobreajusta em dados ruidosos.
P: Como interpretar a importância de features no XGBoost/LightGBM? R: Use
model.feature_importances_(ganho de split) ou SHAP values (mais detalhado). Ganho de split é rápido, mas tem viés em direção a features de alta cardinalidade. SHAP é mais preciso, porém mais lento.
📖 Resumo
- Boosting é um método ensemble sequencial: cada árvore corrige os erros da anterior
- XGBoost: função objetivo regularizada + histograma para velocidade, mas exige encoding categórico
- LightGBM: GOSS + EFB + histograma, 5-10x mais rápido que XGBoost, suporta categorias nativamente
- Hiperparâmetros-chave: learning_rate, n_estimators, max_depth/num_leaves, regularização
- Early stopping é a forma mais simples de evitar sobreajuste
- LightGBM + features categóricas nativas + early stopping é a configuração padrão para o SalesPredict
📝 Exercícios
- Básico (Dificuldade ⭐): Treine um XGBoostRegressor em dados de make_regression e compare o R² com diferentes max_depth (3, 6, 10). Dica: use
cross_val_score. - Intermediário (Dificuldade ⭐⭐): Compare XGBoost e LightGBM em um conjunto de dados de 10 mil linhas em tempo de treino e R². Dica: use
time.time()para medir o tempo. - Desafio (Dificuldade ⭐⭐⭐): Implemente o pipeline completo do modelo principal do Bob — gere dados simulados de e-commerce, construa 5 features (incluindo lag e categóricas), treine LightGBM com early stopping, plote a curva de aprendizado e identifique a iteração ótima. Dica: use
lgb.early_stopping()+model.best_iteration_.
← Anterior: Engenharia de Features | Próximo: Redução de Dimensionalidade — PCA e t-SNE →