Case Passos Mágicos
Este projeto apresenta uma API com um modelo preditivo de Machine Learning supervisionado, desenvolvido para estimar o risco de defasagem escolar de estudantes da Associação Passos Mágicos.
O modelo foi treinado utilizando dados históricos dos alunos para classificar se um estudante possui ou não risco de apresentar defasagem no próximo ano letivo, caracterizando um problema de classificação binária.
Mais sobre a Associação: https://passosmagicos.org.br/quem-somos/
A Base de dados é dataset em formato Excel de pesquisa extensiva do desenvolvimento educacional no período de 2022, 2023 e 2024.
No projeto ela esta localizada junto do seu dicionário de dados em: data\raw
- Linguagem: Python 3.10.11
- Frameworks de ML: scikit-learn, xgboost, pandas, numpy
- API: Flask
- Serialização: pickle
- Testes: pytest
- Empacotamento: Docker
- Deploy: Azure
- Monitoramento: Grafana e Prometheus
API: https://webapp-datathon.azurewebsites.net/
Link Video Explicativo: https://www.youtube.com/watch?v=cxwMEoo9fdI
|-- .github
| `-- workflows
| `-- deploy_azure.yml
|-- app
| |-- model
| |-- routes
| | |-- historical_data.py
| | |-- metrics.py
| | `-- predict.py
| |-- services
| | |-- data_featcher.py
| | |-- download_data.py
| | |-- historical_validators.py
| | `-- predict_validators.py
| |-- __init__.py
| |-- config.py
| `-- main.py
|-- artifacts
| `-- meta.json
|-- data
| |-- processed
| | `-- refined_data.csv
| `-- raw
| `-- BaseDeDadosDatathon.xlsx
|-- models
| `-- model.pkl
|-- notebooks
|-- observability
| |-- grafana
| | |-- dashboards
| | | |-- api-dashboard.json
| | | `-- drift-dashboard.json
| | `-- provisioning
| | |-- dashboards
| | | `-- dashboards.yml
| | `-- datasources
| | `-- datasources.yml
| `-- prometheus
| `-- prometheus.yml
|-- src
| |-- __init__.py
| |-- evaluate.py
| |-- feature_enginnering.py
| |-- preprocessing.py
| |-- run_train.py
| |-- train.py
| `-- utils.py
|-- tests
| |-- conftest.py
| |-- generate_coverage_reports.py
| |-- test_api.py
| `-- test_model.py
|-- docker-compose.yml
|-- Dockerfile
|-- readme.md
`-- requirements.txt
A documentação das rotas com exemplos de chamadas está disponível no Swagger:
Link: https://webapp-datathon.azurewebsites.net/apidocs
- Tipo: GET
- Link: https://webapp-datathon.azurewebsites.net/historical_data?ano_inicio=2022&ano_fim=2024&ra=RA-1&idade=19
- Resultado:
[
{
"ra": "ra-1",
"inde": 5.783,
"idade": 19,
"genero": "F",
"anoIngresso": 2016,
"instituicaoEnsino": "PUBLICA",
"defasagem": -1,
"nAv": 4,
"iaa": 8.3,
"ieg": 4.1,
"ips": 5.6,
"ida": 4.0,
"mat": 2.7,
"por": 3.5,
"ing": 6.0,
"atingiuPV": 0,
"anoReferencia": 2022,
"faseIdealNivel": 8,
"faseAtualNivel": 7,
"destaqueIEG_flag": 0,
"destaqueIDA_flag": 0,
"inde_isnull": 0
}
]- Tipo: POST
- Link: https://webapp-datathon.azurewebsites.net/predict
- Body:
{
"inde": 6.847,
"idade": 16,
"genero": "F",
"anoIngresso": 2018,
"instituicaoEnsino": "PRIVADA",
"nAv": 4,
"iaa": 5.4,
"ieg": 6.3,
"ips": 5.6,
"ida": 8.9,
"mat": 9.5,
"por": 7.7,
"ing": 9.5,
"atingiuPV": 0,
"anoReferencia": 2022,
"destaqueIEG_flag": 0,
"destaqueIDA_flag": 1,
"inde_isnull": 0
}- Resultado:
{
"latency": 0.006134033203125,
"prediction": 1,
"probability": 0.9680503010749817,
"threshold": 0.2829841673374176
}O Risco de defasagem esta em "probability" em percentual, portanto nesse exemplo o aluno tem 96,81% de risco de defasagem
O monitoramento da aplicação é realizado utilizando Grafana, Prometheus e Loki para acompanhar métricas da API e detectar possíveis drifts no modelo de machine learning.
- Grafana: Acesse http://localhost:3000 (usuário: admin, senha: admin)
- Prometheus: Acesse http://localhost:9090
- Loki: Acesse http://localhost:3100
- Métricas de performance da API (latência, throughput, erros)
- Detecção de drift nos dados de entrada do modelo
- Dashboards customizados para visualização em tempo real
O objetivo do modelo é prever risco de defasagem no próximo ano (classificação binária), usando dados do aluno no ano atual.
-
Modelo utilizado e por quê
- XGBoostClassifier
-
Foi escolhido por performar melhor que o baseline de Regressão Logística em dados tabulares com variáveis numéricas/categóricas e interações não-lineares.
-
Além disso, permite controlar desbalanceamento via scale_pos_weight, e costuma entregar bom desempenho sem exigir muitas transformações manuais de features.
-
- XGBoostClassifier
-
Etapas do pipeline
1- Leitura dos dados (Excel)
* Carrega as abas PEDE2022, PEDE2023, PEDE2024.
2- Padronização e limpeza
* Renomeia colunas para um padrão único entre os anos.
* Trata erros de Excel (#N/D, #DIV/0!) como nulos.
* Converte colunas numéricas (ex.: mat, por, ing, iaa, ieg, ips, ida, nAv) para tipo numérico.
3- Feature Engineering
* Cria faseAtualNivel e faseIdealNivel.
* Padroniza categorias (genero, instituicaoEnsino).
* Converte campos textuais em flags binárias:
* atingiuPV → 0/1
* destaqueIEG_flag e destaqueIDA_flag (Destaque/Melhorar) → 1/0
4- Imputação
* Imputa inde quando nulo usando a mediana por (faseAtualNivel, anoReferencia) sob regra do projeto.
5- Construção do target (próximo ano)
* defasagem_bin = 1 se defasagem < 0, senão 0.
* y_next = defasagem_bin do ano seguinte por aluno (shift(-1) por ra).
* Remove linhas sem próximo ano observado.
6- Split temporal (sem vazamento)
* Treino: anoReferencia = 2022 (prevendo 2023)
* Teste: anoReferencia = 2023 (prevendo 2024)
7- Pré-processamento para modelagem
* SimpleImputer (numéricas: mediana; categóricas: mais frequente)
* OneHotEncoder para variáveis categóricas
8- Treinamento
* XGBoost com parâmetros controlados e scale_pos_weight baseado na proporção de classes no treino.
9- Decisão (threshold)
* O threshold é escolhido para maximizar precisão garantindo recall mínimo (ex.: recall ≥ 0.80), de forma a equilibrar captura de alunos em risco com volume de falsos positivos.
10- Persistência de artefatos
* preprocessor.joblib, xgb_model.joblib e meta.json (features + threshold + métricas).
Como o problema é de classificação binária (risco de defasagem no próximo ano), as métricas foram escolhidas para refletir o trade-off entre capturar alunos em risco e evitar alertas excessivos.
-
Métricas utilizadas
-
Precision (classe 1): entre os alunos marcados como “em risco”, quantos realmente defasam.
-
Recall (classe 1): entre os alunos que realmente defasam, quantos o modelo consegue identificar.
-
F1-score (classe 1): equilíbrio entre precision e recall.
-
Accuracy: proporção total de acertos (menos indicada em bases desbalanceadas, mas útil como referência).
-
(Opcional recomendado) ROC-AUC e PR-AUC para avaliar a qualidade do ranqueamento das probabilidades.
-
-
Resultados das métricas (modelo final – XGBoost)
-
Configuração de decisão: threshold escolhido para maximizar precisão com recall ≥ 0.80
-
Matriz de confusão
-
TN = 269, FP = 175
-
FN = 60, TP = 248
-
-
Classification report (teste)
-
Classe 0:
- precision = 0.82 | recall = 0.61 | f1 = 0.70
-
Classe 1:
- precision = 0.59 | recall = 0.81 | f1 = 0.68
-
accuracy = 0.69
-
-
Observação: o threshold é parte essencial do produto. Em cenários de intervenção (educação), normalmente prioriza-se recall (não deixar alunos em risco passarem), ajustando o threshold conforme a capacidade operacional de acompanhamento.
O projeto possui 85 testes automatizados que cobrem 94% do código, garantindo a qualidade e confiabilidade da aplicação.
| Métrica | Valor |
|---|---|
| Cobertura Total | 94% |
| Testes Executados | 85 passed |
| Total de Statements | 638 |
| Statements Não Cobertos | 36 |
| Módulo | Statements | Miss | Cobertura |
|---|---|---|---|
app/__init__.py |
0 | 0 | 100% |
app/config.py |
5 | 0 | 100% |
app/main.py |
19 | 0 | 100% |
app/routes/historical_data.py |
10 | 0 | 100% |
app/routes/metrics.py |
30 | 2 | 93% |
app/routes/predict.py |
64 | 2 | 97% |
app/services/data_featcher.py |
15 | 0 | 100% |
app/services/download_data.py |
25 | 0 | 100% |
app/services/historical_validators.py |
53 | 10 | 81% |
app/services/predict_validators.py |
84 | 8 | 90% |
| Módulo | Statements | Miss | Cobertura |
|---|---|---|---|
src/__init__.py |
0 | 0 | 100% |
src/evaluate.py |
28 | 0 | 100% |
src/feature_enginnering.py |
53 | 5 | 91% |
src/preprocessing.py |
29 | 3 | 90% |
src/run_train.py |
16 | 0 | 100% |
src/train.py |
40 | 0 | 100% |
src/utils.py |
167 | 6 | 96% |
Para executar os testes e gerar relatório de cobertura:
# Executar todos os testes com relatório de cobertura
python -m pytest --cov=app --cov=src tests/ --cov-report=term-missing
# Executar apenas testes da API
pytest --cov=app --cov-report=html:tests/htmlcov_api tests/test_api.py
# Executar apenas testes do modelo
pytest --cov=src --cov-report=html:tests/htmlcov_model tests/test_model.py
# Gerar relatório HTML de cobertura
python tests/generate_coverage_reports.pyOs relatórios HTML são gerados em:
tests/htmlcov_api/- Cobertura dos testes de APItests/htmlcov_model/- Cobertura dos testes do modelo
git clone https://github.com/KaiqueBM/DatathonMLE
Invoke-WebRequest -UseBasicParsing -Uri "https://raw.githubusercontent.com/pyenv-win/pyenv-win/master/pyenv-win/install-pyenv-win.ps1" -OutFile "./install-pyenv-win.ps1"; &"./install-pyenv-win.ps1"
pyenv install 3.10.11
pyenv local 3.10.11
python -m venv venv
venv/Scripts/activate
pip install -r requirements.txt
python --version
python -m app.main
docker compose down
docker compose build --no-cache
docker compose up -d --build


