Um modelo isolado tem limites. Mas o que acontece se você combinar muitos modelos, cada um errando de um jeito diferente? Os erros individuais tendem a se cancelar, e o conjunto acerta mais do que qualquer membro sozinho. Essa é a ideia central dos ensembles — e provavelmente o motivo pelo qual florestas aleatórias e gradient boosting dominam competições e problemas tabulares do mundo real. Esta primeira aula de ensembles foca em bagging e sua realização mais famosa, a Random Forest.
Entender a decomposição viés-variância como fundamento dos ensembles, dominar bagging e random forest (incluindo out-of-bag, importância de variáveis e Extra Trees), e saber quando essas técnicas são a escolha certa.
O que a combinação de modelos resolve: viés e variância
O erro esperado de um modelo se decompõe em três partes:
Erro = Viés² + Variância + Ruído irredutível
- Viés: erro por suposições simplistas (o modelo é rígido demais — underfitting).
- Variância: sensibilidade a flutuações do conjunto de treino (o modelo muda muito com pequenas mudanças nos dados — overfitting).
- Ruído: irredutível, inerente ao problema.
Ensembles atacam essas componentes de formas diferentes: bagging reduz variância; boosting reduz viés. Entender isso é entender qual ensemble usar.
A intuição da sabedoria das multidões
Se você tem M modelos independentes, cada um com erro aleatório, a média das predições tem variância aproximadamente M vezes menor (quando os erros são não-correlacionados). Modelos reais treinados nos mesmos dados não são totalmente independentes, então o ganho é menor — mas a lógica se mantém: quanto mais diversos (descorrelacionados) os modelos, maior o benefício de combiná-los. A diversidade é a matéria-prima do ensemble.
Bagging (Bootstrap Aggregating)
Bagging cria diversidade reamostrando os dados: treina cada modelo em uma amostra bootstrap (sorteada com reposição) do conjunto de treino, e agrega por média (regressão) ou voto (classificação).
from sklearn.ensemble import BaggingClassifier
from sklearn.tree import DecisionTreeClassifier
from sklearn.model_selection import cross_val_score
from sklearn.datasets import make_classification
X, y = make_classification(n_samples=3000, n_features=20, random_state=42)
# Árvore única (alta variância)
arvore = DecisionTreeClassifier(random_state=42)
print("Árvore:", cross_val_score(arvore, X, y, cv=5, scoring="roc_auc").mean())
# Bagging de 200 árvores
bag = BaggingClassifier(DecisionTreeClassifier(),
n_estimators=200, random_state=42, n_jobs=-1)
print("Bagging:", cross_val_score(bag, X, y, cv=5, scoring="roc_auc").mean())
Bagging funciona melhor com modelos de alta variância e baixo viés — como árvores profundas. Cada árvore overfitta de um jeito diferente (por ver dados diferentes), e a média cancela esse overfitting. Aplicar bagging a modelos estáveis e de alto viés (regressão linear) traz pouco benefício.
Random Forest — bagging turbinado
Random Forest adiciona uma segunda fonte de diversidade sobre o bagging: em cada divisão (split) de cada árvore, apenas um subconjunto aleatório de features é considerado. Isso descorrelaciona ainda mais as árvores — sem essa restrição, se houvesse uma feature muito forte, quase toda árvore a usaria no topo, tornando-as parecidas.
from sklearn.ensemble import RandomForestClassifier
rf = RandomForestClassifier(
n_estimators=500, # número de árvores: mais = melhor até saturar
max_features="sqrt", # features por split: √p é padrão em classificação
max_depth=None, # árvores profundas (baixo viés)
min_samples_leaf=1,
n_jobs=-1, random_state=42,
)
print("RF:", cross_val_score(rf, X, y, cv=5, scoring="roc_auc").mean())
Hiperparâmetros que importam:
n_estimators: mais árvores nunca pioram o desempenho (só o custo); aumente até saturar.max_features: o principal controle de diversidade.sqrt(classificação) ou1/3(regressão) são padrões; menor → mais diversidade/menos correlação.max_depth/min_samples_leaf: controlam a complexidade de cada árvore.
Out-of-Bag (OOB) — validação de graça
Cada amostra bootstrap deixa de fora ~37% dos dados (aqueles não sorteados). Esses exemplos "out-of-bag" servem como um conjunto de validação natural: cada árvore é avaliada nos dados que não viu, dando uma estimativa de desempenho sem precisar de CV separada.
rf = RandomForestClassifier(n_estimators=500, oob_score=True,
random_state=42, n_jobs=-1).fit(X, y)
print(f"OOB score: {rf.oob_score_:.3f}")
Por que ~37%? A probabilidade de uma amostra específica não ser sorteada em n tentativas com reposição é (1 − 1/n)ⁿ → 1/e ≈ 0.368. O OOB é conveniente, embora a CV continue sendo o padrão-ouro para comparações rigorosas.
Importância de variáveis em florestas — com cautela
Random forests fornecem duas medidas de importância:
import numpy as np
from sklearn.inspection import permutation_importance
# 1. Importância por impureza (MDI) — rápida, mas ENVIESADA
imp_mdi = rf.feature_importances_
# 2. Importância por permutação — mais confiável
perm = permutation_importance(rf, X, y, n_repeats=10, random_state=42, n_jobs=-1)
imp_perm = perm.importances_mean
print("Top features (permutação):", np.argsort(imp_perm)[-5:])
Alerta crítico: a importância por impureza (MDI, o feature_importances_ padrão) é enviesada a favor de features de alta cardinalidade (muitos valores distintos) e infla features correlacionadas. Para decisões importantes, prefira permutation importance (calculada em dados de validação) ou SHAP (Módulo 8). Este é um erro comuníssimo — confiar cegamente no feature_importances_.
Extra Trees — ainda mais aleatoriedade
Extremely Randomized Trees levam a aleatoriedade adiante: além de subconjunto de features, os pontos de corte de cada split são escolhidos aleatoriamente (em vez de otimizados). Isso reduz ainda mais a variância (ao custo de um leve aumento de viés) e treina mais rápido.
from sklearn.ensemble import ExtraTreesClassifier
et = ExtraTreesClassifier(n_estimators=500, random_state=42, n_jobs=-1)
print("ExtraTrees:", cross_val_score(et, X, y, cv=5, scoring="roc_auc").mean())
Voting e a base do stacking
Você também pode combinar modelos de tipos diferentes — a diversidade vem da variedade de algoritmos, não só dos dados.
from sklearn.ensemble import VotingClassifier
from sklearn.linear_model import LogisticRegression
from sklearn.svm import SVC
voto = VotingClassifier(
estimators=[
("rf", RandomForestClassifier(n_estimators=200, random_state=42)),
("lr", LogisticRegression(max_iter=1000)),
("svc", SVC(probability=True, random_state=42)),
],
voting="soft", # média das probabilidades (melhor que voto "hard")
n_jobs=-1,
)
print("Voting:", cross_val_score(voto, X, y, cv=5, scoring="roc_auc").mean())
- Hard voting: voto majoritário das classes.
- Soft voting: média das probabilidades (geralmente superior, pois usa a confiança de cada modelo).
O stacking generaliza isso: em vez de média fixa, um meta-modelo aprende a melhor forma de combinar.
Quando usar bagging/RF
Random Forest é uma excelente baseline forte: robusta, pouco sensível a hiperparâmetros, lida bem com features em escalas diferentes (não precisa padronizar), captura não-linearidades e interações, e raramente overfitta com muitas árvores. Fraquezas: modelos grandes (memória/latência), extrapolação ruim fora do intervalo de treino (regressão), e costuma ser superada por gradient boosting bem sintonizado em dados tabulares.
Em R
library(tidymodels)
rf_spec <- rand_forest(trees = 500, mtry = tune(), min_n = tune()) |>
set_engine("ranger", importance = "permutation") |>
set_mode("classification")
# ranger é a implementação rápida de random forest em R;
# importance="permutation" já pede a importância confiável.
O erro se decompõe em viés ao quadrado, variância e ruído, e é essa decomposição que separa as duas famílias: bagging reduz variância, boosting reduz viés. O que faz um ensemble ganhar é a diversidade — modelos descorrelacionados, que erram de formas diferentes. O bagging treina cada modelo numa amostra bootstrap e agrega, brilhando justamente com modelos de alta variância, como árvores profundas. O Random Forest é bagging mais sorteio de features a cada divisão, e é esse sorteio que descorrelaciona as árvores; max_features é o controle central de diversidade. De brinde vem o OOB, uma estimativa de validação praticamente de graça, já que cerca de 37% dos dados ficam de fora de cada árvore. Um cuidado: o feature_importances_ por MDI é enviesado pela cardinalidade — prefira permutation importance. E há vizinhos úteis: as Extra Trees acrescentam aleatoriedade nos próprios cortes, e o voting, sobretudo o soft, combina modelos distintos e já antecipa a ideia do stacking.
Exercícios
-
Explique por que bagging reduz principalmente a variância e não o viés, e por que isso o torna eficaz com árvores profundas.
✓ Resposta:Bagging treina múltiplos modelos em amostras bootstrap diferentes e agrega suas predições (média/voto). A média de estimadores com erro aleatório reduz a variância do conjunto (os erros idiossincráticos de cada modelo tendem a se cancelar), mas não altera sistematicamente o viés — se todos os modelos têm o mesmo viés, a média mantém esse viés. Árvores de decisão profundas têm baixo viés e alta variância (ajustam-se muito aos dados, overfittando de formas diferentes conforme o subconjunto visto). São o caso ideal para bagging: a agregação corta a variância excessiva sem introduzir viés, resultando em um modelo com baixo viés e variância reduzida. Aplicar bagging a modelos de alto viés e baixa variância (ex.: regressão linear) traz pouco ganho.
-
Qual é a fonte extra de aleatoriedade que a Random Forest adiciona ao bagging comum, e por que ela melhora o ensemble?
✓ Resposta:Além de reamostrar os dados (bagging), a Random Forest, em cada split de cada árvore, considera apenas um subconjunto aleatório das features (controlado por
max_features). Isso descorrelaciona as árvores: sem essa restrição, se existisse uma ou duas features muito preditivas, quase todas as árvores as escolheriam no topo, ficando parecidas — e a média de árvores correlacionadas reduz pouco a variância. Ao forçar cada split a olhar features diferentes, árvores distintas exploram sinais diferentes, aumentando a diversidade. Como o benefício da agregação cresce com a descorrelação entre membros, essa aleatoriedade extra melhora o desempenho do ensemble. -
O que é a estimativa out-of-bag (OOB) e de onde vem o número ~37%?
✓ Resposta:Cada árvore é treinada em uma amostra bootstrap (sorteio com reposição do mesmo tamanho do dataset). Algumas amostras não são sorteadas para uma dada árvore — são as "out-of-bag" daquela árvore. Avaliando cada exemplo apenas nas árvores que não o viram no treino, obtém-se uma estimativa de desempenho sem precisar de um conjunto de validação separado. O ~37% vem da probabilidade de uma amostra específica não ser escolhida em n sorteios com reposição: (1 − 1/n)ⁿ, que converge para 1/e ≈ 0,368 quando n cresce. Assim, em média ~37% dos dados ficam de fora de cada árvore e servem para a estimativa OOB.
-
Por que confiar cegamente em
feature_importances_(importância por impureza) de uma Random Forest pode levar a conclusões erradas?✓ Resposta:A importância por impureza (MDI) mede quanto cada feature reduz a impureza nos splits, acumulada sobre as árvores. Ela é enviesada: (a) favorece features de alta cardinalidade (muitos valores distintos, como variáveis contínuas ou IDs), que têm mais oportunidades de criar splits que reduzem impureza mesmo sem sinal real; (b) infla ou distribui de forma instável a importância entre features correlacionadas; (c) é calculada no próprio treino, podendo refletir overfitting. Isso pode fazer uma feature irrelevante mas de alta cardinalidade parecer importante. A alternativa mais confiável é a permutation importance (medida em dados de validação, avaliando a queda de desempenho ao embaralhar cada feature) ou valores SHAP.
-
Qual a diferença entre hard voting e soft voting, e por que soft voting costuma ser melhor?
✓ Resposta:No hard voting, cada modelo vota em uma classe e a classe majoritária vence — só a decisão final de cada modelo conta. No soft voting, tomam-se as probabilidades previstas por cada modelo e faz-se a média; a classe com maior probabilidade média vence. Soft voting costuma ser melhor porque usa a confiança de cada modelo: um modelo muito seguro (prob. 0,95) pesa mais na média do que um em cima do muro (prob. 0,51), enquanto no hard voting ambos contribuiriam com um único voto igual. Isso aproveita mais informação e geralmente melhora o desempenho — desde que as probabilidades sejam razoavelmente calibradas (ver Módulo 2).
Fontes e leituras recomendadas
- scikit-learn — Ensembles
- Breiman (2001) — Random Forests
- Geurts et al. (2006) — Extremely Randomized Trees
- ranger — fast random forests in R
- Hastie, Tibshirani, Friedman — ESL, cap. 15 (Random Forests)
- scikit-learn — Permutation importance