Previsão de Adoção de Pets com Machine Learning: O que os Dados (Não) Revelam 🐾
Ao iniciarmos um projeto de Ciência de Dados, é comum focarmos todas as nossas energias na busca pela maior métrica de acerto. No entanto, a verdadeira maturidade analítica surge quando percebemos que um modelo também serve para nos dizer o que não funciona.
Neste artigo, compartilho a jornada de construção de um pipeline robusto de Machine Learning que desenvolvi com a equipe DataMind (composta por mim, Bruno Said e Waleska) para o projeto final do Bootcamp em Ciência de Dados da Avanti.ia.
📌 O Desafio de Negócio
Toda a nossa análise foi guiada por uma "Pergunta de Ouro":
"Quando um animal entra pela porta do abrigo, quanto tempo estimamos que ele vai ocupar uma vaga e gerar custos?" O nosso objetivo inicial era permitir que a gestão de um abrigo de animais pudesse prever os dias de permanência (TimeInShelterDays). Isso permitiria estimar custos operacionais diários, gerenciar as baias de forma inteligente e planejar campanhas proativas. Optamos, portanto, por uma abordagem de Regressão.🛠️ Engenharia de Dados e Pré-processamento
Para garantir que a base de dados estava pronta para a modelagem, criamos um Pipeline de pré-processamento avançado utilizando a biblioteca Scikit-Learn.
1. Engenharia de Features Começamos expandindo as nossas variáveis de 10 para 14, criando features lógicas como WeightAgeRatio (Relação Peso/Idade), IsYoung (É jovem), IsSenior (É idoso) e HealthScore (Pontuação de Saúde).
2. Tratamento de Outliers com POO Em vez de simplesmente apagar linhas de forma manual, desenvolvemos uma classe customizada utilizando o método IQR para fazer o clipping dinâmico de outliers. Um excelente exemplo da fusão entre Ciência de Dados e a Programação Orientada a Objetos no Python:
Python
# Classe para tratamento de outliers usando método IQR
class OutlierClipper(BaseEstimator, TransformerMixin):
def __init__(self, factor=1.5):
self.factor = factor
self.lower_bounds = {}
self.upper_bounds = {}
def fit(self, X, y=None):
for col in range(X.shape[1]):
Q1 = np.percentile(X[:, col], 25)
Q3 = np.percentile(X[:, col], 75)
IQR = Q3 - Q1
self.lower_bounds[col] = Q1 - self.factor * IQR
self.upper_bounds[col] = Q3 + self.factor * IQR
return self
3. O Pipeline Orquestramos tudo em um ColumnTransformer, integrando SimpleImputer para dados faltantes, RobustScaler para variáveis contínuas, e OneHotEncoder e OrdinalEncoder para dados categóricos.
⚔️ A Batalha dos 7 Modelos
Com os dados limpos, iniciamos os testes de algoritmos. Avaliamos sete modelos: Regressão Linear, Ridge, K-Nearest Neighbors (KNN), Decision Tree, Random Forest, Gradient Boosting (GBR) e Support Vector Regressor (SVR).
Para garantir a robustez e evitar que o nosso modelo ficasse dependente de uma única divisão de dados de treino e teste, aplicamos uma validação cruzada do tipo ShuffleSplit com 30 iterações. Paralelamente, utilizamos o RandomizedSearchCV para realizar o tuning automatizado dos hiperparâmetros.
Avaliamos as métricas de Erro Médio Absoluto (MAE), Erro Médio Quadrático (MSE), Coeficiente de Determinação (R²) e o Erro Percentual Médio Absoluto (MAPE).
Os resultados em termos de Erro Absoluto Médio (MAE) situaram-se na casa dos 22 dias para todos os algoritmos. O SVR apresentou o erro mais baixo (22,18 dias) e o Random Forest o mais alto (22,66 dias). O MSE girou em torno de 660.
E é aqui que a magia (ou a realidade) dos dados acontece.
🚀 O Grande Achado (O Plot Twist Analítico)
Mesmo com um pré-processamento rigoroso e com o ajuste de parâmetros refinado, reparamos que a métrica R² em todos os modelos estacionou em valores levemente negativos (entre -0,003 e -0,05).
O que um R² negativo nos diz na prática? Ele indica que as variáveis disponíveis não foram suficientes para explicar adequadamente a variabilidade da nossa variável alvo. Basicamente, os nossos modelos ultracomplexos tiveram um desempenho equivalente ao de tentar prever o tempo de adoção apostando simplesmente na média histórica.
E ao contrário do que se possa pensar, esta é uma conclusão estatística de extremo valor.
Nós provamos, de forma rigorosa, que a biologia e os dados cadastrais do pet (idade, peso, cor ou raça) não ditam o seu tempo de espera para a adoção. Um modelo de Machine Learning não pode aprender um padrão que simplesmente não existe nos dados fornecidos.
Um bom cientista de dados não força métricas para agradar o negócio, mas sim traduz a realidade dos dados: no mundo real, a adoção depende de variáveis externas que não constam neste dataset, como as condições econômicas do bairro, a qualidade das fotos nas campanhas de adoção, ou até a lotação momentânea do próprio abrigo.
🔭 Próximos Passos na Jornada
O projeto não termina aqui. Como trabalhos futuros, planejamos:
- Realizar ajustes de hiperparâmetros ainda mais aprofundados com técnicas como o GridSearchCV.
- Explorar ainda mais técnicas de engenharia de atributos para extrair mais valor do dataset.
- Avaliar métodos ensemble mais robustos na busca por eventuais ganhos de performance.
Espero que este compartilhamento seja útil para quem está estudando modelos preditivos. Nem sempre o R² vai ser de 0.90, mas os insights de negócio valem seu peso em ouro.
🔗 Repositório do projeto com todo o código fonte: karlarenatadev/projeto-final-bootcamp-avantiia-ciencia-de-dados
E vocês? Já enfrentaram projetos onde os dados mostraram que o comportamento não correspondia à expectativa inicial? Compartilhem suas experiências nos comentários!



