from sklearn.datasets import load_iris
from sklearn.model_selection import train_test_split
from sklearn.tree import DecisionTreeClassifier
from sklearn.metrics import accuracy_score, classification_report
iris = load_iris()
X, y = iris.data, iris.target
X_train, X_test, y_train, y_test = train_test_split(
X,
y,
test_size=0.3,
random_state=42,
stratify=y
)6 Poda e Overfitting
Árvores de decisão aprendem rápido, mas justamente por isso podem crescer demais. Quando a árvore continua criando divisões para capturar detalhes muito específicos do treino, ela deixa de representar padrões gerais e passa a memorizar ruído. Esse fenômeno é o overfitting.
6.1 O que é overfitting
Overfitting acontece quando o modelo se ajusta excessivamente aos dados de treinamento e perde capacidade de generalização. Em uma árvore, isso aparece de maneira muito visível: a estrutura fica profunda, ramificada e cheia de folhas com poucas amostras.
6.2 Sinais típicos
- desempenho excelente no treino;
- desempenho bem pior no teste;
- árvore muito alta ou com muitas folhas;
- regras muito específicas e pouco intuitivas;
- alta sensibilidade a pequenas mudanças nos dados.
6.3 Por que árvores sofrem com isso
Como a construção é gulosa e local, a árvore aceita novas divisões sempre que elas parecem melhorar a pureza dos nós. Sem restrições, esse processo continua até restarem grupos muito pequenos ou totalmente puros no treino.
Em muitos casos, pureza extrema no treino significa apenas memorização.
6.4 Pré-poda
Pré-poda significa impedir que a árvore cresca demais desde o início.
6.4.1 Hiperparâmetros mais usados
max_depth: limita quantos níveis a árvore pode ter;min_samples_split: exige um mínimo para tentar nova divisão;min_samples_leaf: garante um mínimo por folha;max_leaf_nodes: controla o número total de folhas;min_impurity_decrease: exige ganho mínimo de qualidade.
6.4.2 Exemplo
from sklearn.tree import DecisionTreeClassifier
pre_pruned = DecisionTreeClassifier(
max_depth=4,
min_samples_split=10,
min_samples_leaf=5,
random_state=42
)
pre_pruned.fit(X_train, y_train)DecisionTreeClassifier(max_depth=4, min_samples_leaf=5, min_samples_split=10,
random_state=42)In a Jupyter environment, please rerun this cell to show the HTML representation or trust the notebook. On GitHub, the HTML representation is unable to render, please try loading this page with nbviewer.org.
Parameters
6.5 Pos-poda
Pós-poda significa deixar a árvore crescer mais e depois remover ramos que não compensam sua complexidade. No scikit-learn, isso aparece na poda por custo-complexidade usando ccp_alpha.
A ideia é equilibrar duas forças:
- erro de ajuste;
- tamanho da árvore.
Quanto maior o ccp_alpha, maior a penalização da complexidade e menor tende a ficar a árvore.
6.6 Caminho de poda
path = DecisionTreeClassifier(random_state=42).cost_complexity_pruning_path(X_train, y_train)
ccp_alphas = path.ccp_alphas
models = []
for alpha in ccp_alphas:
clf = DecisionTreeClassifier(random_state=42, ccp_alpha=alpha)
clf.fit(X_train, y_train)
models.append(clf)
print("Total de modelos testados:", len(models))
print("Primeiros alphas:", ccp_alphas[:10])Total de modelos testados: 5
Primeiros alphas: [0. 0.00899471 0.01848739 0.2788671 0.33333333]
6.7 Comparando alphas na prática
results = []
for alpha in ccp_alphas:
clf = DecisionTreeClassifier(random_state=42, ccp_alpha=alpha)
clf.fit(X_train, y_train)
train_score = clf.score(X_train, y_train)
test_score = clf.score(X_test, y_test)
results.append((alpha, clf.get_depth(), clf.get_n_leaves(), train_score, test_score))
for row in results[:10]:
print(row)(np.float64(0.0), 5, np.int64(8), 1.0, 0.9333333333333333)
(np.float64(0.008994708994708996), 3, np.int64(4), 0.9809523809523809, 0.9333333333333333)
(np.float64(0.01848739495798319), 2, np.int64(3), 0.9714285714285714, 0.8888888888888888)
(np.float64(0.27886710239651413), 1, np.int64(2), 0.6666666666666666, 0.6666666666666666)
(np.float64(0.33333333333333354), 0, np.int64(1), 0.3333333333333333, 0.3333333333333333)
A comparação acima mostra algo valioso: conforme o alpha cresce, a árvore simplifica. Em algum ponto, simplificar ajuda a generalizar; depois disso, simplificar demais passa a reduzir desempenho.
6.8 Como escolher ccp_alpha
O jeito mais seguro é usar validação cruzada. A escolha não deve depender apenas do score no treino ou de uma única divisão teste.
6.9 Complexidade versus interpretabilidade
Poda não serve apenas para melhorar desempenho. Ela também deixa o modelo mais fácil de explicar. Em ambientes corporativos, uma árvore um pouco menos precisa, mas muito mais clara, pode ser preferível a uma estrutura enorme e difícil de justificar.
6.10 Exemplo de leitura de negócio
Uma árvore de churn sem poda pode produzir dezenas de regras microespecíficas. Depois da poda, talvez sobrem algumas regras fortes, como:
- muitos chamados ao suporte aumentam risco de cancelamento;
- pouco tempo de contrato combinado com alto gasto aumenta vulnerabilidade;
- clientes antigos com baixo atrito tendem a permanecer.
Essas regras são muito mais acionáveis.
6.11 Underfitting também existe
Nem toda simplificação é boa. Se limitarmos demais a profundidade ou exigirmos folhas muito grandes, a árvore pode se tornar incapaz de capturar padrões importantes. Isso produz underfitting: desempenho ruim até mesmo no treino.
6.12 Sinais de underfitting
- baixa acurácia no treino e no teste;
- árvore rasa demais;
- regras excessivamente genéricas;
- incapacidade de separar grupos claramente distintos.
6.13 Estratégia prática recomendada
Uma abordagem equilibrada costuma ser:
- treinar uma árvore inicial para entender o problema;
- medir profundidade, número de folhas e desempenho em treino e teste;
- ajustar
max_depth,min_samples_leafemin_samples_split; - testar poda com
ccp_alpha; - escolher o ponto em que simplicidade e desempenho ficam bem equilibrados.
- Overfitting aparece quando a árvore memoriza detalhes do treino.
- Pré-poda impede crescimento excessivo desde o início.
- Pós-poda simplifica a árvore depois do treino.
- O melhor ponto costuma equilibrar simplicidade, desempenho e interpretabilidade.
Uma boa árvore não é necessariamente a maior nem a mais pura no treino. É a que consegue representar os padrões relevantes sem se prender a detalhes acidentais. No próximo capítulo, vamos ver como essa lógica aparece tanto em classificação quanto em regressão.
- concluir que mais profundidade sempre melhora o modelo;
- podar demais e gerar underfitting;
- escolher
ccp_alphaolhando apenas treino; - ignorar folhas com poucas amostras.
- Como reconhecer sinais de overfitting em uma árvore?
- O que diferencia pre-poda e pos-poda?
- Qual o papel de
ccp_alpha? - Por que uma árvore mais simples pode ser preferível em negócio?