9  Exercícios Práticos

Este capítulo foi pensado para transformar leitura em domínio real do assunto. Tente resolver os exercícios sem consultar imédiatamente o gabarito. O ganho maior vem do processo de pensar nas escolhas do modelo.

9.1 Exercício 1: intuição estrutural

Explique com suas palavras:

  • o que representa a raiz de uma árvore;
  • o que significa um nó ser puro;
  • por que uma folha pode ser entendida como uma decisão final;
  • por que uma árvore muito grande pode generalizar pior.

9.2 Exercício 2: Gini e entropia

Considere um nó com 12 exemplos, dos quais 9 pertencem a classe A e 3 a classe B.

  1. Calcule a impureza Gini.
  2. Calcule a entropia.
  3. Explique o que esses valores dizem sobre a pureza do nó.
  4. Compare com um nó contendo 6 exemplos de cada classe.

9.3 Exercício 3: primeira árvore no Iris

Treine uma DecisionTreeClassifier no Iris com max_depth=3.

  • Compare com o modelo sem limite de profundidade.
  • Avalie accuracy e f1_macro.
  • Compare profundidade e número de folhas.
  • Interprete a diferenca entre simplicidade e desempenho.

9.4 Exercício 4: leitura da árvore

Depois de treinar o modelo no Iris:

  • plote a árvore;
  • identifique o atributo da raiz;
  • escreva duas regras da raiz até folhas;
  • diga por que esses atributos parecem informativos.

9.5 Exercício 5: validação cruzada

Use cross_val_score com cv=5 para comparar os seguintes modelos:

  • DecisionTreeClassifier(max_depth=2)
  • DecisionTreeClassifier(max_depth=3)
  • DecisionTreeClassifier(max_depth=5)
  • DecisionTreeClassifier()

Responda:

  • qual profundidade teve melhor média?
  • qual configuração pareceu mais estavel?
  • ha evidencias de overfitting nas configurações mais profundas?

9.7 Exercício 7: poda por custo-complexidade

No mesmo problema:

  • gere o caminho de ccp_alpha;
  • treine várias árvores com alphas diferentes;
  • compare profundidade, número de folhas e desempenho;
  • tente encontrar o ponto em que a simplificação ainda preserva a qualidade.

9.8 Exercício 8: regressão sintética

Crie um problema com make_regression e compare:

  • DecisionTreeRegressor(max_depth=3)
  • DecisionTreeRegressor(max_depth=6)
  • DecisionTreeRegressor(max_depth=10)
  • DecisionTreeRegressor()

Avalie com:

  • MAE
  • MSE
  • R2

Explique o efeito do aumento da profundidade.

9.9 Exercício 9: estudo de caso de churn

No dataset sintético do capítulo anterior:

  • teste min_samples_leaf em [1, 5, 10, 20];
  • compare max_depth em [3, 4, 5, 6, None];
  • verifique quais variáveis mais aparecem na parte superior da árvore;
  • escreva três interpretações de negócio a partir das regras aprendidas.

9.10 Exercício 10: critica de modelo

Escreva um pequeno parecer técnico respondendo:

  • quando uma árvore isolada e uma boa escolha;
  • quando ela pode ser insuficiente;
  • em que situações voce priorizaria interpretabilidade;
  • quando faria sentido migrar para Random Forest ou Gradient Boosting.

9.11 Gabarito inicial para apoio

O objetivo do gabarito abaixo não e entregar todas as respostas, mas fornecer um ponto de partida para implementação.

from sklearn.datasets import load_iris, make_regression
from sklearn.model_selection import train_test_split, cross_val_score, GridSearchCV
from sklearn.tree import DecisionTreeClassifier, DecisionTreeRegressor
from sklearn.metrics import accuracy_score, f1_score, mean_absolute_error, r2_score

# Classificação com Iris
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,
    stratify=y
)

for depth in [None, 3]:
    clf = DecisionTreeClassifier(max_depth=depth, random_state=42)
    clf.fit(X_train, y_train)
    pred = clf.predict(X_test)
    print(
        f"depth={depth} | acc={accuracy_score(y_test, pred):.3f} | "
        f"f1_macro={f1_score(y_test, pred, average='macro'):.3f} | "
        f"depth_real={clf.get_depth()} | leaves={clf.get_n_leaves()}"
    )

# Validação cruzada
for depth in [2, 3, 5, None]:
    clf = DecisionTreeClassifier(max_depth=depth, random_state=42)
    scores = cross_val_score(clf, X, y, cv=5, scoring="accuracy")
    print(f"depth={depth} | média={scores.mean():.3f} | desvio={scores.std():.3f}")

# Grid search
param_grid = {
    "max_depth": [2, 3, 4, 5, None],
    "min_samples_split": [2, 5, 10],
    "min_samples_leaf": [1, 2, 4],
    "criterion": ["gini", "entropy"]
}

grid = GridSearchCV(
    DecisionTreeClassifier(random_state=42),
    param_grid=param_grid,
    cv=5,
    scoring="accuracy",
    n_jobs=-1
)
grid.fit(X_train, y_train)
print(grid.best_params_)

# Regressão
X_reg, y_reg = make_regression(n_samples=500, n_features=5, noise=20, random_state=42)
X_train_reg, X_test_reg, y_train_reg, y_test_reg = train_test_split(
    X_reg,
    y_reg,
    test_size=0.2,
    random_state=42
)

for depth in [3, 6, 10, None]:
    reg = DecisionTreeRegressor(max_depth=depth, random_state=42)
    reg.fit(X_train_reg, y_train_reg)
    pred_reg = reg.predict(X_test_reg)
    print(
        f"depth={depth} | MAE={mean_absolute_error(y_test_reg, pred_reg):.2f} | "
        f"R2={r2_score(y_test_reg, pred_reg):.3f}"
    )
depth=None | acc=0.933 | f1_macro=0.933 | depth_real=5 | leaves=8
depth=3 | acc=0.978 | f1_macro=0.978 | depth_real=3 | leaves=5
depth=2 | média=0.933 | desvio=0.047
depth=3 | média=0.973 | desvio=0.025
depth=5 | média=0.953 | desvio=0.034
depth=None | média=0.953 | desvio=0.034
{'criterion': 'gini', 'max_depth': 3, 'min_samples_leaf': 1, 'min_samples_split': 2}
depth=3 | MAE=47.65 | R2=0.689
depth=6 | MAE=53.99 | R2=0.645
depth=10 | MAE=54.69 | R2=0.645
depth=None | MAE=53.80 | R2=0.667

Use esse bloco como base e amplie as respostas conceituais por escrito. Em aprendizado de maquina, saber justificar a escolha do modelo e tao importante quanto executar o código.

ImportantDicas
  • resolva primeiro sem consultar o gabarito;
  • escreva as respostas conceituais em texto, não apenas em código;
  • compare suas solucoes com os principios vistos nos capítulos teóricos;
  • revise especialmente os exercícios em que a estrutura da árvore ficou diferente do esperado.
WarningErros comuns
  • responder apenas com código, sem interpretação;
  • comparar modelos sem relatar metricas e profundidade;
  • esquecer de justificar por que um hiperparametro funcionou melhor;
  • tratar o gabarito como resposta final em vez de ponto de partida.
TipPerguntas de revisão
  1. Voce consegue calcular entropia e Gini manualmente em exemplos simples?
  2. Voce consegue explicar diferencas entre ID3, C4.5 e CART?
  3. Voce sabe treinar, visualizar e podar uma árvore em Python?
  4. Voce consegue transformar uma árvore em regras compreensíveis para negócio?