Machine Learning: Árvores de Decisão e Florestas Aleatórias

Última atualização: 2026-08-26

Uma árvore de decisão é como uma árvore de perguntas — cada nó faz uma pergunta, e você segue a resposta até uma folha, que é a sua previsão.

1. O que você vai aprender


2. A história real de um gerente de produto de e-commerce

(1) O problema: previsão de produtos de sucesso dependia totalmente de intuição, com uma taxa de acerto inferior a 30%

O Bob precisava escolher produtos em potencial para serem sucesso de vendas entre 1 mil novos itens. No passado, isso era puro julgamento, e sua taxa de acerto era de apenas 30%. Cada produto de sucesso traz em média 500 mil USD de receita mensal, então perder um é uma perda enorme. A intuição não pode ser quantificada, reutilizada ou iterada.

(2) A solução com Floresta Aleatória

Uma Floresta Aleatória pode descobrir automaticamente padrões de produtos de sucesso a partir de dados históricos de produtos — faixa de preço, características da categoria, tendências de vendas da primeira semana — e naturalmente fornece um ranking de importância das features.

PYTHON
from sklearn.ensemble import RandomForestClassifier

rf = RandomForestClassifier(n_estimators=100, oob_score=True, random_state=42)
rf.fit(X_train, y_train)
print(f"OOB Accuracy: {rf.oob_score_:.3f}")
print(f"Feature mais importante: {feature_names[rf.feature_importances_.argmax()]}")

(3) O resultado: a precisão na previsão de produtos de sucesso subiu de 30% para 65%

O Bob substituiu a intuição por uma Floresta Aleatória, elevando a precisão da previsão de produtos de sucesso de 30% para 65%. Ele agora identifica 5 produtos de sucesso extras por mês, acrescentando cerca de 3 milhões de USD em receita anual.


3. Como funcionam as árvores de decisão

(1) Critérios de divisão

Em cada nó, uma árvore de decisão escolhe a melhor feature e limiar para fazer a divisão. Existem três critérios comuns:

100%
graph TB
    ROOT[Nó Raiz<br/>Todos os Dados] --> SPLIT1{Feature: preco<br/>Limiar: 50 USD}
    SPLIT1 -->|≤ 50| LEFT[Filho Esquerdo<br/>60% produtos de sucesso]
    SPLIT1 -->|> 50| RIGHT[Filho Direito<br/>10% produtos de sucesso]
    LEFT --> SPLIT2{Feature: vendas_primeira_semana}
    SPLIT2 -->|> 500| LEAF1[Folha: SUCESSO<br/>90% confiança]
    SPLIT2 -->|≤ 500| LEAF2[Folha: NÃO SUCESSO<br/>40% confiança]
    RIGHT --> LEAF3[Folha: NÃO SUCESSO<br/>5% confiança]
Critério Fórmula central Preferência Família de algoritmos
Ganho de informação $H(D) - H(D A)$ Favorece features com muitos valores
Razão de ganho Ganho de informação / Valor intrínseco Corrige o viés de multi-valor C4.5
Impureza de Gini $1 - \sum p_i^2$ Favorece pureza de classes grandes CART

▶ Exemplo: Classificação com árvore de decisão na Iris

PYTHON
from sklearn.tree import DecisionTreeClassifier, plot_tree
from sklearn.datasets import load_iris
from sklearn.model_selection import train_test_split
from sklearn.metrics import accuracy_score, classification_report
import matplotlib.pyplot as plt

iris = load_iris()
X_train, X_test, y_train, y_test = train_test_split(
    iris.data, iris.target, test_size=0.3, random_state=42, stratify=iris.target
)

# Treinar com pré-poda
tree = DecisionTreeClassifier(max_depth=3, min_samples_leaf=5, random_state=42)
tree.fit(X_train, y_train)

y_pred = tree.predict(X_test)
print(f"Acurácia: {accuracy_score(y_test, y_pred):.4f}")
print(f"Profundidade da árvore: {tree.get_depth()}")
print(f"Número de folhas: {tree.get_n_leaves()}")

# Visualizar a árvore
fig, ax = plt.subplots(figsize=(14, 8))
plot_tree(tree, feature_names=iris.feature_names,
          class_names=iris.target_names, filled=True, rounded=True, ax=ax)
plt.title("Árvore de Decisão (max_depth=3)")
plt.tight_layout()
plt.savefig("decision_tree.png", dpi=150)

Saída:

TEXT 📖 Somente leitura
# Executa com sucesso

(2) Estratégias de poda

▶ Exemplo: Comparando parâmetros de pré-poda

PYTHON
from sklearn.tree import DecisionTreeClassifier
from sklearn.model_selection import cross_val_score
from sklearn.datasets import load_iris

X, y = load_iris(return_X_y=True)

configs = {
    "Sem poda": DecisionTreeClassifier(random_state=42),
    "max_depth=2": DecisionTreeClassifier(max_depth=2, random_state=42),
    "max_depth=3": DecisionTreeClassifier(max_depth=3, random_state=42),
    "min_samples_leaf=5": DecisionTreeClassifier(min_samples_leaf=5, random_state=42),
    "max_depth=3 + min_samples_leaf=5": DecisionTreeClassifier(
        max_depth=3, min_samples_leaf=5, random_state=42),
}

for name, model in configs.items():
    scores = cross_val_score(model, X, y, cv=5, scoring="accuracy")
    model.fit(X, y)
    print(f"{name:35s}: Acurácia={scores.mean():.3f}, Folhas={model.get_n_leaves()}")

Saída:

TEXT 📖 Somente leitura
# Executa com sucesso
Tipo de poda Parâmetro Efeito Valor recomendado
Pré-poda max_depth Limita a profundidade da árvore 3-10
Pré-poda min_samples_leaf Amostras mínimas por folha 5-20
Pré-poda min_samples_split Amostras mínimas para dividir 10-40
Pré-poda max_features Features consideradas por divisão sqrt(n_features)
Pós-poda ccp_alpha Poda por custo-complexidade Escolha via GridSearch

4. Floresta Aleatória

(1) A ideia de Bagging

Floresta Aleatória = Bagging (Bootstrap Aggregating) + seleção aleatória de features.

100%
graph TB
    DATA[Dados Originais] --> B1[Amostra Bootstrap 1]
    DATA --> B2[Amostra Bootstrap 2]
    DATA --> B3[Amostra Bootstrap 3]
    DATA --> BN[Amostra Bootstrap N]
    B1 --> T1[Árvore 1<br/>Subconjunto Aleatório de Features]
    B2 --> T2[Árvore 2<br/>Subconjunto Aleatório de Features]
    B3 --> T3[Árvore 3<br/>Subconjunto Aleatório de Features]
    BN --> TN[Árvore N<br/>Subconjunto Aleatório de Features]
    T1 --> VOTE[Voto por Maioria<br/>/ Média]
    T2 --> VOTE
    T3 --> VOTE
    TN --> VOTE

▶ Exemplo: Classificação com Floresta Aleatória + avaliação OOB

PYTHON
from sklearn.ensemble import RandomForestClassifier
from sklearn.datasets import load_iris
from sklearn.model_selection import train_test_split
from sklearn.metrics import accuracy_score

X, y = load_iris(return_X_y=True)
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.3, random_state=42)

rf = RandomForestClassifier(
    n_estimators=100,
    max_depth=None,
    oob_score=True,
    random_state=42,
)
rf.fit(X_train, y_train)

print(f"OOB Score: {rf.oob_score_:.4f}")
print(f"Acurácia no Teste: {accuracy_score(y_test, rf.predict(X_test)):.4f}")
print(f"Número de árvores: {rf.n_estimators}")

Saída:

TEXT 📖 Somente leitura
# Executa com sucesso

(2) Ajuste de hiperparâmetros

▶ Exemplo: Regressão com Floresta Aleatória — Previsão de vendas do SalesPredict

PYTHON
from sklearn.ensemble import RandomForestRegressor
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 = 500
X = rng.uniform(0, 100, (n, 6))
y = 50 + 0.8 * X[:, 0] + 1.2 * X[:, 1] - 0.5 * 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)

# Comparar diferentes n_estimators
for n_est in [10, 50, 100, 200]:
    rf = RandomForestRegressor(n_estimators=n_est, random_state=42, n_jobs=-1)
    rf.fit(X_train, y_train)
    score = rf.score(X_test, y_test)
    mae = mean_absolute_error(y_test, rf.predict(X_test))
    print(f"n_estimators={n_est:3d}: R²={score:.4f}, MAE={mae:.2f}")

Saída:

TEXT 📖 Somente leitura
# Executa com sucesso

5. Análise de importância das features

(1) Diminuição Média de Impureza vs. Importância por Permutação

▶ Exemplo: Comparando os dois métodos de importância de features

PYTHON
from sklearn.ensemble import RandomForestClassifier
from sklearn.inspection import permutation_importance
from sklearn.datasets import load_iris
import matplotlib.pyplot as plt
import numpy as np

X, y = load_iris(return_X_y=True)
feature_names = load_iris().feature_names

rf = RandomForestClassifier(n_estimators=100, random_state=42)
rf.fit(X, y)

# Método 1: MDI (embutido, rápido, mas com viés)
mdi_importance = rf.feature_importances_

# Método 2: Importância por permutação (mais lento, mas mais confiável)
perm_result = permutation_importance(rf, X, y, n_repeats=30, random_state=42, n_jobs=-1)
perm_importance = perm_result.importances_mean

# Comparar
fig, axes = plt.subplots(1, 2, figsize=(14, 5))

y_pos = np.arange(len(feature_names))
axes[0].barh(y_pos, mdi_importance, color="#2196F3")
axes[0].set_yticks(y_pos)
axes[0].set_yticklabels(feature_names)
axes[0].set_title("Importância MDI")

axes[1].barh(y_pos, perm_importance, color="#4CAF50")
axes[1].set_yticks(y_pos)
axes[1].set_yticklabels(feature_names)
axes[1].set_title("Importância por Permutação")

plt.tight_layout()
plt.savefig("feature_importance.png", dpi=150)

Saída:

TEXT 📖 Somente leitura
# Executa com sucesso
Dimensão Importância MDI Importância por Permutação
Velocidade de cálculo Rápida (calculada durante o treino) Lenta (exige previsões repetidas)
Viés Com viés em direção a features de alta cardinalidade Sem viés
Aplicabilidade Embutida em modelos de árvore Funciona com qualquer modelo
Confiabilidade Moderada Mais confiável

▶ Exemplo: Ranking de features para previsão de produtos de sucesso do Bob

PYTHON
from sklearn.ensemble import RandomForestClassifier
import pandas as pd
import numpy as np

rng = np.random.default_rng(42)
n = 1000
df = pd.DataFrame({
    "price_usd": rng.uniform(10, 200, n),
    "first_week_sales": rng.integers(10, 2000, n),
    "category_trend_score": rng.uniform(0, 1, n),
    "ad_budget_k": rng.uniform(1, 50, n),
    "review_score": rng.uniform(1, 5, n),
    "return_rate": rng.uniform(0, 0.3, n),
    "stock_depth": rng.integers(10, 500, n),
})

df["is_hit"] = (
    (df["first_week_sales"] > 500)
    & (df["category_trend_score"] > 0.6)
    & (df["price_usd"] < 100)
).astype(int) | (rng.random(n) < 0.05)  # Adicionar 5% de ruído

X = df.drop(columns=["is_hit"])
y = df["is_hit"]

rf = RandomForestClassifier(n_estimators=200, random_state=42)
rf.fit(X, y)

importance = pd.DataFrame({
    "feature": X.columns,
    "importance": rf.feature_importances_,
}).sort_values("importance", ascending=False)

print("Importância das Features para Previsão de Produtos de Sucesso:")
print(importance.to_string(index=False))

Saída:

TEXT 📖 Somente leitura
Importância das Features para Previsão de Produtos de Sucesso:

❓ Perguntas Frequentes

P: Por que uma Floresta Aleatória é melhor do que uma única árvore de decisão? R: Por duas razões — 1) Bagging reduz a variância (várias árvores votam e tiram a média); 2) a seleção aleatória de features diminui a correlação entre as árvores, tornando o ensemble mais forte. Uma única árvore tende a sobreajustar.

P: Um n_estimators maior é sempre melhor? R: Não necessariamente. Passado um certo ponto, os ganhos diminuem e você só adiciona tempo de computação. Normalmente 100-500 é suficiente. Observe o OOB score para ver quando ele se estabiliza.

P: O que é o OOB Score? R: Avaliação Out-of-Bag. Cada árvore é treinada com cerca de 63% dos dados, e os 37% restantes formam naturalmente um conjunto de validação. O OOB Score é a média de previsões entre todas as árvores em suas próprias amostras OOB — equivalente à validação cruzada, mas gratuita.

P: Árvores de decisão precisam de normalização? R: Não. Árvores de decisão fazem divisões por limiares de features, então não são afetadas pela escala. Mas se uma Floresta Aleatória for combinada com outros modelos (como um Scaler em um Pipeline), então você pode precisar dela.

P: E se todas as importâncias de features forem próximas de 0? R: Isso sugere que as features podem genuinamente ter pouca relação com o alvo. Tente interações entre features ou transformações não lineares, ou use a importância por permutação para verificar se o MDI está viesado.

P: Uma Floresta Aleatória consegue lidar com desbalanceamento de classes? R: Sim. Defina class_weight="balanced" ou class_weight={0:1, 1:10}. Você também pode combiná-la com oversampling (SMOTE) ou undersampling.


📖 Resumo


📝 Exercícios

  1. Básico (Dificuldade ⭐): Use DecisionTreeClassifier para classificar a Iris, variando max_depth de 1 a 5, e plote a curva de acurácia vs. profundidade. Dica: itere sobre o treino com cross_val_score.
  2. Intermediário (Dificuldade ⭐⭐): Use RandomForestRegressor no California Housing, comparando R² e OOB Score para n_estimators=[10,50,100,200]. Dica: defina oob_score=True.
  3. Desafio (Dificuldade ⭐⭐⭐): Implemente o pipeline completo de previsão de produtos de sucesso do Bob — gere dados simulados, treine um RandomForestClassifier, analise features com permutation_importance, lide com desbalanceamento com class_weight (produtos de sucesso < 10%) e produza um classification report. Dica: consulte o exemplo de produtos de sucesso na Seção 5.

← Anterior: Regressão Logística | Próximo: Máquinas de Vetores de Suporte →

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%