As árvores de decisão são modelos de aprendizado de máquina versáteis, capazes de realizar tanto tarefas de classificação quanto de regressão. Elas operam através de uma lógica de divisões sucessivas no conjunto de dados, criando uma estrutura hierárquica que se assemelha a um fluxograma.
Estrutura de um Modelo de Árvore
- Nó Raiz: Representa o ponto inicial e a primeira grande divisão baseada na característica mais discriminativa.
- Nós Internos (Decisão): Pontos intermediários onde o fluxo de dados é direcionado para diferentes ramificações conforme condições específicas.
- Ramos: Conexões que representam o resultado de uma regra de decisão.
- Folhas: Nós terminais que contêm o veredito final ou o valor predito.
Critérios de Seleção e Divisão
O principal desafio na construção de uma árvore de decisão é determinar qual atributo deve ser testado em cada nó. Para isso, utilizamos medidas de pureza ou incertzea.
Entropia e Ganho de Informação
A Entropia mede o nível de desordem ou aleatoriedade nos dados. Em um sistema binário, se os dados estiverem divididos exatamente em 50/50, a entropia é máxima (1). Se todos os dados pertencerem a uma única classe, a entropia é 0.
O Ganho de Informação é a redução da entropia alcançada após a divisão dos dados por um determinado atributo. O algoritmo busca maximizar esse ganho para tornar os nós subsequentes o mais homogêneos possível.
Problema de Identificadores Únicos
Atributos com muitos valores distintos (como IDs de usuários) podem gerar um ganho de informação artificialmente alto, mas não possuem poder preditivo real. Para mitigar isso, utiliza-se a Razão de Ganho ou o Índice Gini, que penaliza divisões excessivamente ramificadas.
Estratégias de Poda (Pruning)
Árvores de decisão tendem a crescer excessivamente, capturando ruídos do conjunto de treinamento, o que leva ao overfitting. A poda é essencial para a generalização do modelo.
- Pré-poda: Define critérios de parada durante a fase de crescimento, como profundidade máxima, número mínimo de amostras por nó ou ganho de informação mínimo.
- Pós-poda: Permite que a árvore cresça completamente e, em seguida, remove os ramos que contribuem pouco para a precisão em dados de validação.
Implementação Prática com Scikit-Learn
Abaixo, demonstramos a construção de um regressor baseado em árvore utilizando o conjunto de dados de habitação da Califórnia.
import pandas as pd
from sklearn.datasets import fetch_california_housing
from sklearn.tree import DecisionTreeRegressor, export_graphviz
from sklearn.model_selection import train_test_split
# Carregamento do dataset
dados_california = fetch_california_housing()
X = dados_california.data
y = dados_california.target
# Configuração e treinamento inicial
# Limitamos a profundidade para evitar complexidade excessiva
regressor_arvore = DecisionTreeRegressor(max_depth=3, random_state=42)
regressor_arvore.fit(X[:, [0, 5]], y) # Usando apenas duas colunas para exemplo
Visualização do Modelo
Para interpretar como o modelo toma decisões, podemos exportar a estrutura da árvore.
import graphviz
# Gerando a representação visual
dados_dot = export_graphviz(
regressor_arvore,
out_file=None,
feature_names=['Renda_Mediana', 'Ocupacao_Media'],
filled=True,
rounded=True,
special_characters=True
)
visualizacao = graphviz.Source(dados_dot)
# visualizacao.render("arvore_decisao_habitacao")
Otimização e Busca de Hiperparâmetros
Na prática, utilizamos técnicas de validação cruzada para encontrar a melhor configuração de hiperparâmetros, frequentemente utilizando Random Forests para maior estabilidade.
from sklearn.ensemble import RandomForestRegressor
from sklearn.model_selection import GridSearchCV
# Divisão em treino e teste
X_treino, X_teste, y_treino, y_teste = train_test_split(X, y, test_size=0.2, random_state=123)
# Definição da grade de busca
grade_parametros = {
'n_estimators': [10, 50, 100],
'max_features': ['sqrt', 'log2'],
'min_samples_split': [2, 5, 10]
}
# Busca exaustiva com Cross-Validation
busca_grid = GridSearchCV(RandomForestRegressor(random_state=42), grade_parametros, cv=5)
busca_grid.fit(X_treino, y_treino)
print(f"Melhor pontuação: {busca_grid.best_score_}")
print(f"Melhores parâmetros: {busca_grid.best_params_}")
Ao ajustar parâmetros como min_samples_split e n_estimators, conseguimos equilibrar a capacidade de aprendizado do modelo com sua habilidade de lidar com dados nunca vistos, garantindo uma performence robusta em ambiente de produção.