Readmissão Hospitalar de Diabéticos
Uma base de dados clínica famosa e irregular: alvo raro, sinal fraco, 97% de ausência em uma coluna, 716 códigos de diagnóstico e pacientes repetidos. Até onde vai uma regressão logística bem especificada contra o gradient boosting — medindo com todas as métricas que importam?
- base de dados
- Diabetes 130-US Hospitals 1999–2008 (UCI · Strack et al., 2014)
- tarefa
- classificação binária · readmissão em até 30 dias (11,4%)
- modelo principal
- regressão logística · log das contagens + B-splines cúbicos · L2
- comparados
- variantes de RL (6) · floresta aleatória · LightGBM · + 3 RLs enriquecidas
- validação
- divisão, CV e bootstrap por paciente (StratifiedGroupKFold)
- modelo no hub
- huggingface.co/igorlimamillis/diabetes-readmission-logistic
Em poucas palavras
Uma base famosa que não facilita
Nos EUA, hospitais são penalizados quando o paciente volta em até 30 dias. Sinalizar na alta os diabéticos de maior risco permitiria à equipe ligar para eles, revisar a medicação ou antecipar uma consulta. A base Diabetes 130-US Hospitals da UCI (101.766 internações, 1999–2008) é a referência pública para esse problema — e é difícil.
A pergunta aqui não é “qual algoritmo ganha o ranking”, e sim até onde vai uma regressão logística bem especificada, o que o gradient boosting acrescenta e o que cada métrica de fato revela quando o alvo é raro e o sinal é fraco.
| irregularidade | evidência | o que foi feito |
|---|---|---|
| alvo raro e fraco | 11,4% readmitidos em < 30 dias; melhor AUC ≈ 0,68 | regras de escore próprias, PR AUC, calibração; limiares escolhidos fora do fold |
| óbitos e hospice | 2.423 internações não podem ser readmitidas | removidas — senão morrer parece “proteger” |
| pacientes repetidos | 69.987 pacientes; 46% das internações de reincidentes | divisão, ajuste e bootstrap por paciente |
| ausência massiva | peso 97% · glicose 95% · HbA1c 83% · especialidade 49% · pagador 40% | peso descartado; “não medido” mantido como nível |
| códigos de alta cardinalidade | 716 diagnósticos CID-9 primários · 72 especialidades | 9 capítulos do CID-9; 12 especialidades principais; níveis raros agrupados por fold |
| caudas pesadas | internações prévias 0–21 · idas ao PS 0–76 | log1p + B-splines cúbicos dentro do pipeline |
| IDs guardados como números | admissão / alta / origem são códigos nominais | mapeados para grupos com sentido clínico |
Auditoria do arquivo bruto (101.766 internações). Coorte após exclusões: 99.340 internações, 69.987 pacientes.
Dividir por paciente — e verificar se fez diferença
Quase metade das internações é de pacientes vistos mais de uma vez. Uma divisão aleatória põe a mesma pessoa no treino e no teste, e um modelo flexível pode reconhecer pessoas em vez de aprender risco. Por isso o teste tem 13.998 pacientes nunca vistos no treino, os hiperparâmetros são ajustados com StratifiedGroupKFold de 5 folds e os intervalos de confiança vêm de um bootstrap por paciente.
Depois, medi quanto o atalho teria custado:
Um resultado nulo, relatado como tal. Dividir por internação em vez de por paciente inflou a AUC de CV em no máximo 0,0016 — mesmo em uma floresta com folhas de tamanho 1, feita para memorizar. Nenhuma variável identifica o paciente, então há pouco a memorizar. A divisão agrupada continua sendo a certa (é a única que responde “como isso funciona em pacientes novos?”), mas aqui o custo do erro foi pequeno. A AUC de teste fica 0,006–0,009 acima da de CV para todos os modelos igualmente: uma característica desta divisão, não de algum modelo.
Um único pipeline de variáveis, oito modelos
A engenharia de variáveis é uma função linha a linha (faixas de idade → anos, códigos CID-9 → capítulos, IDs de alta → destinos, contagem de medicamentos) no início de cada Pipeline do scikit-learn. Tudo o que é aprendido dos dados — padronização, bases de splines, agrupamento de níveis raros — é ajustado dentro de cada fold. Os hiperparâmetros de todos os modelos são escolhidos nos mesmos folds agrupados pela log loss — uma regra de escore própria —, e não pela acurácia.
| modelo | o que é | hiperparâmetros escolhidos | log loss (CV) |
|---|---|---|---|
| RL · log + splines (principal) | log1p(contagens) → B-splines cúbicos, one-hot nas categóricas, L2 | C=0,010 | 0,3380 |
| RL · splines + L1/L2 | mesmas variáveis, penalização elastic net (solver saga) | C=0,100, l1_ratio=1,000 | 0,3378 |
| RL · termos lineares | contagens brutas padronizadas, one-hot, L2 | C=0,010 | 0,3383 |
| RL · splines + class_weight | RL principal com class_weight=“balanced” | C=0,010 | 0,6490 |
| LightGBM | gradient boosting, busca aleatória com 30 configurações | subsample_freq=1, subsample=1,000, reg_lambda=1,000, num_leaves=31, n_estimators=800, min_child_samples=100, learning_rate=0,010, colsample_bytree=0,800 | 0,3337 |
| Floresta aleatória | 400 árvores, grade de 6 configurações | max_features=0,300, min_samples_leaf=20 | 0,3345 |
| RL · só internações prévias | uma variável: internações no ano anterior | — | — |
CV de 5 folds agrupada nos pacientes de treino. Log loss menor é melhor; o modelo só com a prevalência obtém 0,3537 no teste. Fonte: results/results.json (cv).
O elastic net escolhido é L1 puro e mantém 142 dos 201 coeficientes — esparsidade sem perda. Repare na RL com pesos de classe: mesmas variáveis, mesmo ranking, o dobro da log loss. A seção 06 explica por quê.
O boosting vence por 0,01 de AUC — diferença real e pequena
Nos pacientes de teste, o LightGBM chega a AUC ROC 0,681 e a regressão logística principal a 0,670. Tomando o acaso (0,5) como ponto de partida, a logística mantém 94% do ganho que o boosting alcança — com cerca de 200 coeficientes que podem ser lidos, auditados e entregues como fórmula. Uma variável sozinha (internações prévias) já chega a 0,611.
Métricas de ordenação (sem limiar)
| modelo | AUC ROC | IC 95% | Gini | KS | PR AUC | lift PR | sensib. nos 10% de maior risco | sensib. nos 20% de maior risco | lift nos 10% de maior risco |
|---|---|---|---|---|---|---|---|---|---|
| RL · log + splines (principal) | 0,670 | [0,656; 0,683] | 0,340 | 0,249 | 0,218 | 1,93× | 23,0% | 38,8% | 2,30× |
| RL · splines + L1/L2 | 0,671 | [0,658; 0,684] | 0,343 | 0,253 | 0,219 | 1,93× | 22,8% | 39,0% | 2,28× |
| RL · termos lineares | 0,670 | [0,656; 0,683] | 0,340 | 0,246 | 0,222 | 1,96× | 22,7% | 38,9% | 2,27× |
| RL · splines + class_weight | 0,670 | [0,656; 0,683] | 0,340 | 0,248 | 0,217 | 1,91× | 22,8% | 38,9% | 2,28× |
| LightGBM | 0,681 | [0,668; 0,693] | 0,361 | 0,259 | 0,242 | 2,13× | 25,5% | 40,3% | 2,55× |
| Floresta aleatória | 0,676 | [0,663; 0,690] | 0,353 | 0,259 | 0,239 | 2,10× | 24,0% | 40,6% | 2,40× |
| RL · só internações prévias | 0,611 | [0,597; 0,627] | 0,223 | 0,191 | 0,184 | 1,63× | 21,3% | 35,1% | 2,13× |
| Só a prevalência | 0,500 | — | 0,000 | 0,000 | 0,113 | 1,00× | 10,0% | 20,0% | 1,00× |
PR AUC = precisão média; lift PR = PR AUC / prevalência (0,1135). Sensibilidade nos k% de maior risco = fração de todas as readmissões encontradas entre os k% de internações com maior risco previsto.
Métricas probabilísticas (regras de escore próprias)
| modelo | Brier | IC 95% | ganho no Brier | log loss | ganho na log loss | inclinação de discriminação |
|---|---|---|---|---|---|---|
| RL · log + splines (principal) | 0,0962 | [0,0925; 0,0997] | 4,4% | 0,3347 | 5,4% | 0,043 |
| RL · splines + L1/L2 | 0,0962 | [0,0925; 0,0997] | 4,4% | 0,3345 | 5,4% | 0,044 |
| RL · termos lineares | 0,0961 | [0,0924; 0,0996] | 4,4% | 0,3348 | 5,4% | 0,043 |
| RL · splines + class_weight | 0,2254 | [0,2232; 0,2276] | -124,1% | 0,6453 | -82,4% | 0,086 |
| LightGBM | 0,0950 | [0,0914; 0,0985] | 5,6% | 0,3305 | 6,6% | 0,051 |
| Floresta aleatória | 0,0953 | [0,0917; 0,0988] | 5,2% | 0,3316 | 6,2% | 0,047 |
| RL · só internações prévias | 0,0973 | [0,0935; 0,1010] | 3,3% | 0,3416 | 3,4% | 0,031 |
| Só a prevalência | 0,1006 | — | 0,0% | 0,3537 | 0,0% | 0,000 |
Ganho = melhora em relação ao modelo só com a prevalência (negativo = pior que prever 11,4% para todos). Inclinação de discriminação = p̂ médio nos readmitidos − p̂ médio nos não readmitidos (R² de Tjur).
Diferenças pareadas vs. a RL principal (mesmas reamostragens)
| modelo − RL · splines | Δ AUC ROC | Δ PR AUC | Δ Brier | Δ log loss | veredito (AUC) |
|---|---|---|---|---|---|
| RL · splines + L1/L2 | +0,002 [0,000; 0,002] | +0,000 [-0,001; 0,002] | −0,00003 [-0,00008; 0,00003] | −0,0002 [-0,0004; 0,0000] | melhor |
| RL · termos lineares | −0,000 [-0,003; 0,003] | +0,004 [-0,001; 0,008] | −0,00006 [-0,00035; 0,00018] | +0,0001 [-0,0007; 0,0009] | empate |
| RL · splines + class_weight | +0,000 [-0,001; 0,001] | −0,001 [-0,003; 0,000] | +0,12922 [0,12599; 0,13273] | +0,3106 [0,3023; 0,3197] | empate |
| LightGBM | +0,011 [0,006; 0,016] | +0,024 [0,016; 0,034] | −0,00119 [-0,00162; -0,00083] | −0,0041 [-0,0056; -0,0029] | melhor |
| Floresta aleatória | +0,007 [0,000; 0,013] | +0,020 [0,012; 0,031] | −0,00086 [-0,00130; -0,00049] | −0,0030 [-0,0045; -0,0017] | melhor |
| RL · só internações prévias | −0,059 [-0,069; -0,049] | −0,034 [-0,042; -0,026] | +0,00113 [0,00062; 0,00170] | +0,0069 [0,0050; 0,0088] | pior |
Diferença pontual e intervalo de 95% por bootstrap de pacientes. Para Brier e log loss, negativo = melhor que a RL principal.
A logística consegue fechar a lacuna? O boosting ganha duas coisas de graça: códigos de alta cardinalidade e interações. Dei as duas à regressão logística — os códigos CID-9 de 3 dígitos (~700 níveis, raros agrupados) e interações sugeridas pelas árvores (pares de log-contagens, uso prévio × destino da alta):
Fechando a lacuna: logísticas mais ricas
| modelo | coeficientes | log loss (CV) | AUC ROC (teste) | Δ AUC vs RL · splines | Δ AUC vs LightGBM | PR AUC | Brier | inclinação de cal. |
|---|---|---|---|---|---|---|---|---|
| RL · log + splines (principal) | 201 | 0,3380 | 0,670 | — | −0,011 | 0,218 | 0,0962 | 1,04 |
| RL · splines + CID-9 de 3 dígitos | 517 | 0,3373 | 0,673 | +0,003 [0,000; 0,006] | −0,008 [-0,014; -0,002] | 0,220 | 0,0960 | 1,04 |
| RL · splines + interações | 251 | 0,3374 | 0,671 | +0,001 [-0,001; 0,004] | −0,010 [-0,014; -0,005] | 0,226 | 0,0959 | 1,03 |
| RL · splines + CID-9 + interações | 567 | 0,3367 | 0,674 | +0,004 [0,001; 0,007] | −0,007 [-0,012; -0,002] | 0,228 | 0,0957 | 1,03 |
| LightGBM | — | 0,3337 | 0,681 | +0,011 | — | 0,242 | 0,0950 | 1,08 |
Mesma divisão, mesmos folds e mesmas reamostragens bootstrap da comparação anterior. Fonte: results/gap.json (scripts/close_the_gap.py).
A logística mais rica fecha cerca de um terço da lacuna (+0,004 de 0,011 de AUC) e ganha mais em PR AUC e log loss, mas o LightGBM continua significativamente à frente. O resto do sinal está em interações de ordem mais alta, que um preditor linear especificado à mão não alcança: nesta base, a interpretabilidade custa cerca de 0,007 de AUC. Se vale a pena pagar esse preço é uma decisão de implantação, não de modelagem.
Todas as métricas da matriz de confusão, em quatro políticas
Métricas de limiar dependem de uma decisão, então a decisão fica explícita. Três limiares são escolhidos nas predições out-of-fold do treino — nunca no teste — e o quarto é o 0,5 padrão da maioria dos tutoriais. Escolha uma política:
| modelo | τ | sinalizados | acurácia | acur. bal. | precisão | sensibilidade | especificidade | VPN | F1 | F2 | MCC | κ | RV+ | RV− | DOR |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| RL · log + splines (principal) | 0,131 | 26,1% | 0,733 | 0,620 | 0,206 | 0,475 | 0,766 | 0,919 | 0,287 | 0,376 | 0,174 | 0,153 | 2,03 | 0,69 | 2,95 |
| RL · splines + L1/L2 | 0,132 | 25,6% | 0,737 | 0,619 | 0,207 | 0,467 | 0,771 | 0,919 | 0,287 | 0,374 | 0,174 | 0,154 | 2,04 | 0,69 | 2,96 |
| RL · termos lineares | 0,130 | 25,2% | 0,736 | 0,611 | 0,202 | 0,450 | 0,773 | 0,917 | 0,279 | 0,362 | 0,163 | 0,145 | 1,98 | 0,71 | 2,78 |
| RL · splines + class_weight | 0,538 | 26,8% | 0,726 | 0,617 | 0,202 | 0,476 | 0,759 | 0,919 | 0,283 | 0,374 | 0,168 | 0,147 | 1,97 | 0,69 | 2,85 |
| LightGBM | 0,140 | 24,1% | 0,751 | 0,626 | 0,219 | 0,464 | 0,788 | 0,920 | 0,297 | 0,379 | 0,187 | 0,169 | 2,19 | 0,68 | 3,21 |
| Floresta aleatória | 0,138 | 27,0% | 0,727 | 0,621 | 0,204 | 0,485 | 0,758 | 0,920 | 0,287 | 0,380 | 0,174 | 0,152 | 2,00 | 0,68 | 2,95 |
| RL · só internações prévias | 0,119 | 32,8% | 0,672 | 0,596 | 0,172 | 0,497 | 0,694 | 0,915 | 0,256 | 0,361 | 0,129 | 0,105 | 1,62 | 0,72 | 2,24 |
τ maximiza o F1 nas predições out-of-fold de cada modelo. Teste, n = 19.773.
| modelo | τ | sinalizados | acurácia | acur. bal. | precisão | sensibilidade | especificidade | VPN | F1 | F2 | MCC | κ | RV+ | RV− | DOR |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| RL · log + splines (principal) | 0,110 | 37,6% | 0,645 | 0,623 | 0,179 | 0,594 | 0,651 | 0,926 | 0,275 | 0,406 | 0,160 | 0,122 | 1,70 | 0,62 | 2,73 |
| RL · splines + L1/L2 | 0,110 | 37,1% | 0,649 | 0,623 | 0,180 | 0,590 | 0,657 | 0,926 | 0,276 | 0,406 | 0,162 | 0,124 | 1,72 | 0,62 | 2,76 |
| RL · termos lineares | 0,106 | 41,2% | 0,617 | 0,621 | 0,173 | 0,627 | 0,615 | 0,928 | 0,271 | 0,411 | 0,156 | 0,113 | 1,63 | 0,61 | 2,69 |
| RL · splines + class_weight | 0,492 | 36,8% | 0,651 | 0,622 | 0,180 | 0,586 | 0,659 | 0,926 | 0,276 | 0,404 | 0,161 | 0,124 | 1,72 | 0,63 | 2,73 |
| LightGBM | 0,115 | 36,2% | 0,657 | 0,624 | 0,183 | 0,583 | 0,666 | 0,926 | 0,278 | 0,405 | 0,164 | 0,127 | 1,75 | 0,63 | 2,79 |
| Floresta aleatória | 0,116 | 38,8% | 0,638 | 0,629 | 0,180 | 0,616 | 0,641 | 0,929 | 0,279 | 0,415 | 0,167 | 0,125 | 1,72 | 0,60 | 2,86 |
| RL · só internações prévias | 0,119 | 32,8% | 0,672 | 0,596 | 0,172 | 0,497 | 0,694 | 0,915 | 0,256 | 0,361 | 0,129 | 0,105 | 1,62 | 0,72 | 2,24 |
τ maximiza sensibilidade + especificidade − 1 fora do fold: mais sinalizações, sensibilidade maior, precisão menor.
| modelo | τ | sinalizados | acurácia | acur. bal. | precisão | sensibilidade | especificidade | VPN | F1 | F2 | MCC | κ | RV+ | RV− | DOR |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| RL · log + splines (principal) | 0,147 | 19,9% | 0,775 | 0,605 | 0,220 | 0,385 | 0,825 | 0,913 | 0,280 | 0,335 | 0,167 | 0,158 | 2,20 | 0,75 | 2,95 |
| RL · splines + L1/L2 | 0,148 | 20,1% | 0,775 | 0,607 | 0,221 | 0,391 | 0,824 | 0,914 | 0,282 | 0,339 | 0,170 | 0,161 | 2,22 | 0,74 | 3,00 |
| RL · termos lineares | 0,141 | 19,7% | 0,776 | 0,605 | 0,221 | 0,384 | 0,826 | 0,913 | 0,280 | 0,334 | 0,167 | 0,159 | 2,21 | 0,75 | 2,96 |
| RL · splines + class_weight | 0,578 | 19,9% | 0,776 | 0,607 | 0,221 | 0,389 | 0,825 | 0,913 | 0,282 | 0,338 | 0,170 | 0,161 | 2,22 | 0,74 | 3,00 |
| LightGBM | 0,152 | 20,1% | 0,777 | 0,615 | 0,228 | 0,404 | 0,825 | 0,915 | 0,292 | 0,350 | 0,181 | 0,171 | 2,31 | 0,72 | 3,20 |
| Floresta aleatória | 0,157 | 19,8% | 0,780 | 0,616 | 0,231 | 0,404 | 0,828 | 0,916 | 0,294 | 0,352 | 0,185 | 0,175 | 2,35 | 0,72 | 3,27 |
| RL · só internações prévias | 0,120 | 13,8% | 0,811 | 0,578 | 0,228 | 0,277 | 0,880 | 0,905 | 0,250 | 0,265 | 0,144 | 0,143 | 2,30 | 0,82 | 2,80 |
τ = percentil 80 dos escores out-of-fold: um orçamento fixo de acompanhamento para 20% das altas.
| modelo | τ | sinalizados | acurácia | acur. bal. | precisão | sensibilidade | especificidade | VPN | F1 | F2 | MCC | κ | RV+ | RV− | DOR |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| RL · log + splines (principal) | 0,500 | 0,2% | 0,887 | 0,504 | 0,541 | 0,009 | 0,999 | 0,887 | 0,018 | 0,011 | 0,058 | 0,014 | 9,19 | 0,99 | 9,26 |
| RL · splines + L1/L2 | 0,500 | 0,2% | 0,887 | 0,504 | 0,512 | 0,009 | 0,999 | 0,887 | 0,018 | 0,012 | 0,057 | 0,014 | 8,20 | 0,99 | 8,27 |
| RL · termos lineares | 0,500 | 0,4% | 0,887 | 0,509 | 0,629 | 0,020 | 0,999 | 0,888 | 0,038 | 0,024 | 0,097 | 0,031 | 13,22 | 0,98 | 13,46 |
| RL · splines + class_weight | 0,500 | 34,9% | 0,665 | 0,621 | 0,183 | 0,565 | 0,678 | 0,924 | 0,277 | 0,399 | 0,162 | 0,127 | 1,76 | 0,64 | 2,73 |
| LightGBM | 0,500 | 0,2% | 0,887 | 0,505 | 0,667 | 0,011 | 0,999 | 0,888 | 0,021 | 0,013 | 0,074 | 0,018 | 15,62 | 0,99 | 15,78 |
| Floresta aleatória | 0,500 | 0,0% | 0,887 | 0,500 | — | 0,000 | 1,000 | 0,887 | 0,000 | 0,000 | 0,000 | 0,000 | — | 1,00 | — |
| RL · só internações prévias | 0,500 | 0,3% | 0,888 | 0,509 | 0,689 | 0,019 | 0,999 | 0,888 | 0,036 | 0,023 | 0,101 | 0,031 | 17,27 | 0,98 | 17,58 |
Com prevalência de 11,4%, modelos calibrados quase nunca chegam a 0,5: acurácia ≈ 0,887, a mesma de prever “não” para todos. Só a RL com pesos de classe se comporta bem aqui — porque suas probabilidades estão infladas.
Duas lições. Primeiro, em um limiar razoável todos os modelos, exceto a referência de uma variável, caem em uma faixa estreita — F1 0,279–0,297, MCC 0,163–0,187: métricas de limiar quase não separam modelos; regras de pontuação próprias e diferenças pareadas por bootstrap separam. Segundo, o paradoxo da acurácia à vista: a melhor “acurácia” na aba 0,5 é dos modelos que não sinalizam quase ninguém.
class_weight é um defeito de calibração, não uma correção do desbalanceamento
Um escore de risco só serve para decidir se “20%” significar 20%. A RL principal e o LightGBM seguem a diagonal (ECE 0,007). A RL com pesos de classe tem a mesma AUC, mas prevê risco médio de 47% para um desfecho que acontece 11% das vezes:
| modelo | p̂ médio | O/E | intercepto | inclinação | ECE | MCE | z de Spiegelhalter | HL χ²(8) | p de HL |
|---|---|---|---|---|---|---|---|---|---|
| RL · log + splines (principal) | 0,114 | 1,00 | -0,001 | 1,043 | 0,0070 | 0,0133 | -0,14 | 14,20 | 0,077 |
| RL · splines + L1/L2 | 0,114 | 1,00 | -0,004 | 1,039 | 0,0084 | 0,0171 | -0,24 | 18,80 | 0,016 |
| RL · termos lineares | 0,114 | 1,00 | -0,002 | 1,083 | 0,0090 | 0,0268 | -0,25 | 35,92 | < 0,001 |
| RL · splines + class_weight | 0,466 | 0,24 | -2,053 | 0,974 | 0,3522 | 0,4769 | -6,05 | 11.113,66 | < 0,001 |
| LightGBM | 0,113 | 1,00 | 0,003 | 1,082 | 0,0067 | 0,0205 | -0,43 | 12,52 | 0,129 |
| Floresta aleatória | 0,114 | 1,00 | -0,004 | 1,086 | 0,0068 | 0,0145 | -0,81 | 13,00 | 0,112 |
| RL · só internações prévias | 0,113 | 1,00 | 0,002 | 1,101 | 0,0111 | 0,0268 | -0,11 | 31,84 | < 0,001 |
Prevalência observada 0,113. O/E = eventos observados / esperados. Intercepto e inclinação de uma recalibração logística (ideal 0 e 1). ECE / MCE = desvio absoluto médio / máximo nos decis. HL = Hosmer–Lemeshow; com n ≈ 20.000 ele rejeita desvios pequenos, então deve ser lido junto com a inclinação e o ECE.
Por que acontece: dar peso w aos positivos desloca o intercepto do logito em cerca de log w e deixa as inclinações quase intactas. A ordenação se preserva; as probabilidades, não. Mover o limiar faz a mesma troca sem destruir as probabilidades. Uma lição menor: os splines não melhoraram a discriminação (0,6698 vs 0,6698), mas melhoraram a calibração — inclinação 1,04 vs 1,08, erro máximo por decil 1,3 vs 2,7 pontos, p de Hosmer–Lemeshow 0,077 vs < 0,001.
O que puxa a readmissão — com erros-padrão honestos
Para interpretar, ajustei um MLG logístico separado com termos legíveis (contagens por unidade, nível mais frequente como referência, 68 parâmetros) usando IRLS escrito do zero em NumPy — Newton–Raphson na log-verossimilhança, com covariância do modelo, sanduíche e clusterizada por paciente. Coeficientes e erros-padrão clusterizados batem com o statsmodels em cerca de 10−14. Termos com |z| > 3,5:
- Internações prévias dominam: OR 1,30 por internação no ano anterior (z = 35,6).
- Para onde o paciente vai depois é o segundo sinal: reabilitação OR 3,7, outra unidade de internação 2,0, casa de repouso 1,5 (vs. casa).
- HbA1c medida > 8 se associa a menor risco (OR 0,86) — em linha com Strack et al.: medir a HbA1c anda junto com acompanhamento mais próximo.
- O agrupamento por paciente pesa de forma desigual: a razão mediana entre EP clusterizado e EP do modelo é 1,02, mas para idas prévias ao PS é 1,54 — os pacientes com muitas idas ao PS são justamente os que voltam.
Associações, não efeitos causais. O modelo preditivo (seção 03) e este modelo inferencial compartilham os dados, não o propósito.
Quando vale a pena usar o modelo?
Uma curva de decisão converte o limiar em uma razão de custos: agir em τ significa que perder uma readmissão custa (1 − τ)/τ vezes um acompanhamento desnecessário. O benefício líquido supera “tratar todos” a partir de τ ≈ 0,05, mas encolhe para perto de zero acima de ~0,25. O modelo se paga em intervenções baratas — uma ligação, uma revisão farmacêutica —, não nas caras.
E a pergunta do tamanho dos dados: reajustar os dois modelos em subconjuntos aleatórios de pacientes mostra onde a flexibilidade extra começa a compensar.
Subgrupos (RL principal, pacientes de teste)
| variável | grupo | n | taxa observada | média prevista | AUC ROC |
|---|---|---|---|---|---|
| idade | 70+ | 8.752 | 11,7% | 12,3% | 0,631 |
| idade | 50–69 | 7.823 | 11,3% | 10,7% | 0,692 |
| idade | <50 | 3.198 | 10,6% | 10,3% | 0,708 |
| raça | branca | 14.813 | 11,7% | 11,5% | 0,667 |
| raça | afro-americana | 3.697 | 10,8% | 11,5% | 0,669 |
| raça | ausente | 447 | 7,2% | 9,6% | 0,638 |
| raça | hispânica | 398 | 9,0% | 10,4% | 0,748 |
| raça | outra | 302 | 10,3% | 9,7% | 0,681 |
| sexo | feminino | 10.726 | 11,4% | 11,5% | 0,674 |
| sexo | masculino | 9.047 | 11,2% | 11,2% | 0,665 |
Grupos com n ≥ 300. A discriminação é mais fraca nos pacientes mais velhos; o grupo “raça ausente” tem risco superestimado.
Reprodutível, testado, publicado
- Código e todos os números: repositório no GitHub ↗ — quatro scripts (download, experimento, fechar a lacuna, figuras) geram
results/results.json; nenhum número desta página foi digitado à mão. - Modelo: Hugging Face Hub ↗ — o pipeline principal serializado com
skops(sem pickle), com model card, métricas e exemplo de uso. - Testes: 23 casos em pytest — agrupamento CID-9, regras da coorte, IRLS vs scikit-learn e statsmodels (coeficientes, EP do modelo e clusterizado), métricas de calibração em dados simulados, fórmula da curva de decisão.
- Limites: dados dos EUA de 1999–2008 com códigos CID-9; readmissões em outros hospitais não aparecem, então o rótulo subestima as readmissões; internações terminadas em óbito ou hospice foram excluídas e não devem ser pontuadas. Não é para uso clínico.
Dados: Strack et al. (2014), UCI Machine Learning Repository, doi:10.24432/C5230J, CC BY 4.0 — baixados em tempo de execução, não redistribuídos.