Triagem de Depressão — Como foi feito (explicado fácil)
Importante: esse modelo NÃO faz diagnóstico. Ele é uma peneira — ajuda a priorizar quais adolescentes precisam de atenção de um profissional antes. É a diferença entre o pronto-socorro com 200 pessoas: alguém precisa decidir quem é avaliado primeiro.
O que é isso, em uma frase?
É um modelo que olha o questionário respondido por um adolescente (sono, ansiedade, isolamento, uso de redes sociais, etc.) e dá uma nota de risco de depressão. Treinado em dataset público Teen Mental Health.
O resultado é uma probabilidade de 0% a 100%, não um sim/não. Por quê? Porque em saúde, "talvez" importa muito. Um aluno com 92% de risco entra na fila na frente do de 12%. É triagem, não veredito.
Por que importa? A escola/serviço de saúde tem 1 psicólogo pra 500 alunos. O modelo ajuda a chegar primeiro em quem tá pior — sem substituir profissional nenhum, e sem rotular o aluno.
Como o modelo aprende o padrão
1 · Entender o "desbalanceio". No dataset, talvez 20% dos adolescentes estejam classificados como "risco alto" e 80% como "não". Se eu treinasse cego, o modelo aprenderia a chutar "não" sempre e teria 80% de acerto parecendo ótimo — mas seria inútil. Acurácia sozinha mente.
2 · Tratar o desbalanceio com SMOTE. A técnica gera "adolescentes sintéticos" da classe minoritária (risco alto), criando combinações realistas entre os existentes. É como pedir pro Photoshop "faz mais 100 fotos parecidas com essas 50 aqui". O modelo passa a ter exemplos suficientes pra aprender o padrão raro.
from imblearn.over_sampling import SMOTE
print("Antes:", y_train.value_counts().to_dict())
# {0: 800, 1: 200} (80% não, 20% sim)
smote = SMOTE(random_state=42)
X_train_bal, y_train_bal = smote.fit_resample(X_train, y_train)
print("Depois:", pd.Series(y_train_bal).value_counts().to_dict())
# {0: 800, 1: 800} (50/50)
3 · Treinar e calibrar a probabilidade. Uso Regressão Logística e Random Forest — os dois retornam probabilidade nativamente. Em saúde, o número final precisa ser confiável: se o modelo diz "78% de risco", isso tem que querer dizer 78% mesmo. Faço calibração com CalibratedClassifierCV.
from sklearn.linear_model import LogisticRegression from sklearn.calibration import CalibratedClassifierCV base = LogisticRegression(max_iter=1000) modelo = CalibratedClassifierCV(base, cv=5, method="isotonic") modelo.fit(X_train_bal, y_train_bal) probas = modelo.predict_proba(X_test)[:, 1] # probabilidade de "risco alto"
4 · Avaliar com ROC-AUC (a métrica que casa com triagem). ROC-AUC mede: dado um adolescente "em risco" e um "sem risco" escolhidos ao acaso, com que probabilidade o modelo dá nota maior ao "em risco"? 1,0 = perfeito · 0,5 = chute. Cheguei a ROC-AUC ≈ 0,99 no conjunto-teste.
from sklearn.metrics import roc_auc_score
auc = roc_auc_score(y_test, probas)
print(f"ROC-AUC: {auc:.3f}") # 0.992
| métrica | resultado |
|---|---|
| ROC-AUC | ≈ 0,99 |
| Recall (sensibilidade) | alto (poucos falsos negativos) |
| Calibração | isotônica via CV 5-fold |
5 · Decidir onde "cortar". A probabilidade é contínua, mas em algum momento precisa virar ação. Em saúde, falso negativo é pior que falso positivo — pior deixar passar um caso real do que chamar um que tá bem. Então escolho o ponto de corte mais sensível: prefiro errar pra cima (mais gente avaliada) do que pra baixo (caso real perdido).
A curva ROC do modelo
Em uma linha: o que esse projeto ensina
Que contexto define métrica. Em saúde, "acertou 99%" não significa nada — o que importa é a sensibilidade (recall) na classe rara, e a calibração da probabilidade. Modelo bom em ML é o que casa com o custo do erro do problema real.
Coisas técnicas que apareceram aqui: classe desbalanceada, SMOTE (oversampling sintético), Regressão Logística, calibração de probabilidade (CalibratedClassifierCV), ROC-AUC, escolha de threshold orientada ao custo do falso negativo.