Aprendizagem de Máquina • UFAL
Lista 1 — Árvores de Decisão, RIPPER e k-Nearest Neighbors
O repositório fabio-linhares/ml consolida a resolução completa da primeira lista de exercícios da disciplina, combinando cálculos manuais, implementações próprias em Python e uma aplicação interativa em Streamlit. O material cobre do preparo dos dados à avaliação crítica dos modelos, documentando cada etapa de forma reprodutível.
Visão Geral do Projeto
A Lista 1 integra o Mestrado em Informática da UFAL e explora diferentes estratégias de modelagem supervisionada. O repositório entrega:
-
Modelagem manual e interpretável das árvores
ID3, C4.5 e CART a partir da base expandida
clientes.csv, com registros fotográficos dos cálculos emsodeusnacausa/. -
Implementações próprias com arquitetura
modular: uma classe
core (
OptimizedDecisionTree) atende aos três algoritmos, wrappers leves expõem as interfaces e a tabela de memoização reduz recomputações. -
Aplicação web interativa (
app.py) publicada em tutu.zerocopia.com.br, permitindo subir datasets, treinar modelos, visualizar métricas e comparar regras. -
Análises adicionais com RIPPER, kNN, avaliação
de overfitting/underfitting e geração de gráficos e matrizes de
confusão automatizadas em
evaluate_models.py.
Como executar e reproduzir os experimentos
Quickstart
-
Clone o repositório e crie um ambiente isolado:
python -m venv venvouconda create --name lista1_ml python=3.12. -
Ative o ambiente (
source venv/bin/activateouconda activate lista1_ml). -
Instale as dependências:
pip install -r requirements.txt. -
Inicie a aplicação:
streamlit run app.pye acessehttp://localhost:8501. -
Para a Questão 3, execute
download_heart_dataset.pycasoheart.csvnão esteja presente.
Estrutura essencial do repositório
Os experimentos são versionados para garantir rastreabilidade entre o estudo manual, o código otimizado e as visualizações que sustentam a análise crítica.
Questão 1 · Construção manual das árvores
O primeiro exercício amplia a base fornecida pelo "gerente" para 30 instâncias e seis atributos, equilibrando as classes Baixo, Moderado e Alto risco. A partir daí, as árvores ID3, C4.5 e CART são construídas manualmente.
-
Dataset:
clientes.csvdocumenta as 30 entradas adicionadas com coerência à distribuição original. A classe alvo possui 12 exemplos de Baixo, 8 de Moderado e 10 de Alto risco. -
Cálculos fundamentais: entropia, ganho de
informação, ganho normalizado e índice Gini são detalhados passo
a passo, com evidências em
sodeusnacausa/. - Árvores finais: o ID3 gera regras específicas (maior tendência ao overfitting), o C4.5 introduz cortes contínuos (ex.: idade) e o CART consolida uma árvore binária com quatro regras legíveis.
- Base de regras: as regras extraídas (R1–R8) evidenciam como renda e histórico de crédito direcionam o risco. Destaque para a regra "SE renda > $35k ENTÃO risco = Baixo" válida para 13 registros.
Questão 2 · Implementação com bibliotecas e código próprio
A solução programática refatora o exercício manual em uma arquitetura modulada, capaz de reproduzir e comparar os algoritmos dentro da aplicação.
-
Motor unificado:
OptimizedDecisionTreecentraliza métricas, cortes contínuos e suporte a dados categóricos. Memoização (classeAdvancedMemoizationTable) elimina recomputações redundantes. -
Wrappers enxutos:
ID3DecisionTree,C45DecisionTreeeCARTDecisionTreeapenas configuram o motor para cada variação, simplificando a comparação. - Precisão vs. código manual: divergências entre árvores manuais e automatizadas são explicadas por empates quebrados automaticamente, busca exaustiva de limiares e controle de profundidade via hiperparâmetros.
| Algoritmo | Tempo de treino médio | Taxa de acerto do cache | Acurácia no teste (70/30) |
|---|---|---|---|
| ID3 | ≈ 0,275 s | 42,7% | 77,78% (melhor equilíbrio de classes) |
| C4.5 | ≈ 0,223 s | 63,0% | 77,78% (precisão menor para classe Moderado) |
| CART | ≈ 0,299 s | 67,4% | 77,78% (regras binárias concisas) |
As matrizes de confusão e as árvores renderizadas (em
resultados_img/) acompanham o relatório e são
exibidas na aplicação, reforçando a análise comparativa das
classes.
Questão 3 · Dataset Heart Disease e RIPPER
A terceira questão migra para o dataset Heart Disease UCI, avaliando regras induzidas diretamente.
-
Preparação resiliente:
download_heart_dataset.pybusca o dataset no OpenML e gera um conjunto sintético compatível se necessário, garantindo queheart.csvesteja disponível. -
Pipeline de avaliação:
heart_disease_ripper.pytreina uma árvore de decisão (DecisionTreeClassifier) limitada a cinco níveis e um modelo RIPPER via bibliotecawittgenstein, exibindo métricas e o conjunto de regras. -
Interface Streamlit: em
app.py, a aba "Análise de Doenças Cardíacas" carrega o dataset, compara acurácia e expõe o ruleset textual do RIPPER, ressaltando sua interpretabilidade face à árvore.
Questões 4 & 5 · Overfitting, Underfitting e o papel do C4.5
Esta parte do estudo reinterpreta os conceitos de sobreajuste e subajuste dentro do contexto das árvores de decisão.
- Overfitting: árvores profundas (ex.: ID3 sem poda) aderem ao ruído, apresentando acurácia alta em treino e queda no teste.
- Underfitting: estruturas excessivamente simplificadas falham em capturar o padrão — baixa performance em ambos os conjuntos.
- C4.5 como antídoto: poda pessimista, tratamento criterioso de atributos contínuos e limites mínimos por nó balanceiam variância e viés.
-
Memoização e hiperparâmetros: controles como
max_depthe cache de métricas permitem experimentar rapidamente diferentes combinações e observar o trade-off.
A documentação compara as matrizes de confusão resultantes e destaca as classes mais afetadas pela poda agressiva, justificando a escolha cuidadosa dos hiperparâmetros dentro da aplicação.
k-NN na prática · Exploração interativa
A aplicação Streamlit inclui uma seção dedicada para investigar o comportamento do k-NN no dataset cardíaco.
-
Explorador interativo: usuários entram com
novos pontos e visualizam vizinhos mais próximos, retornados por
KNNClassifier. - Análise de sensibilidade: o painel "🔬 Overfitting/Underfitting com k" gera um gráfico da acurácia em função de diferentes valores de k, reforçando empiricamente os conceitos das Questões 4 & 5.
- Insights principais: valores baixos de k (ex.: 1) sofrem com variância alta; valores elevados amortecem demais as fronteiras, levando ao underfitting; o equilíbrio ocorre na região intermediária.
Questão 6 · Fundamentação do k-Nearest Neighbors
Além da experimentação, a lista descreve com detalhes o algoritmo k-NN.
- Exemplo numérico resolvido: demonstração passo a passo das distâncias euclidianas para um ponto candidato considerando k = 1, 3 e 7.
- Escolha do hiperparâmetro: recomendações que vão da regra empírica k ≈ √N à validação cruzada sistemática.
- Limitações da distância euclidiana: para dados mistos, a distância de Gower é sugerida por normalizar atributos numéricos e lidar com categorias.
- Perfis lazy vs. eager: comparação entre k-NN (treino mínimo, inferência custosa) e modelos como árvores ou SVM (treino custoso, inferência rápida).
Tudo isso está implementado em knn_classifier.py,
garantindo que os exemplos teóricos possam ser reproduzidos
diretamente em código.
Notas finais e referências
-
Documentação visual: matrizes de confusão e
árvores exportadas estão em
resultados_img/; os cálculos manuais permanecem registrados emsodeusnacausa/. - Pré-processamento: a codificação simples (LabelEncoder) favorece a didática. Em cenários produtivos, recomenda-se avaliar One-Hot Encoding e normalização.
-
Dependências:
requirements.txtreúne bibliotecas como Streamlit, scikit-learn, pandas, seaborn, graphviz e wittgenstein, refletindo o ecossistema usado nas análises. - Próximos passos: ampliar os testes com validação cruzada e incluir métricas adicionais (F1 macro, MCC) podem aprofundar o diagnóstico das classes minoritárias.