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


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.

PYTHON
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

100%
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

PYTHON
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:

TEXT 📖 Somente leitura
# Executado com sucesso

4. XGBoost em Profundidade

(1) Função Objetivo Regularizada

100%
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

PYTHON
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:

TEXT 📖 Somente leitura
# Executado com sucesso

(2) Early Stopping

▶ Exemplo: Evitar sobreajuste com early stopping

PYTHON
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:

TEXT 📖 Somente leitura
# Executado com sucesso

5. LightGBM — O Mais Rápido

(1) GOSS e EFB

100%
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

PYTHON
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:

TEXT 📖 Somente leitura
# Executado com sucesso

(2) Suporte Nativo a Features Categóricas

▶ Exemplo: LightGBM com features categóricas

PYTHON
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:

TEXT 📖 Somente leitura
# 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

PYTHON
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:

TEXT 📖 Somente leitura
# Executado com sucesso

7. Modelo Principal do Bob: Pipeline Completo do SalesPredict

▶ Exemplo: Construindo o modelo de produção

PYTHON
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:

TEXT 📖 Somente leitura
# 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


📝 Exercícios

  1. 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.
  2. 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.
  3. 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 →

Web-Tutorial.com

Equipe Técnica Web-Tutorial

Uma plataforma de tutoriais mantida por diversos desenvolvedores. Cada tutorial é escrito e revisado por profissionais da área correspondente. Trabalhamos para manter nosso conteúdo preciso e confiável — se encontrar algum problema, avise-nos.

100%