igor-millis~/work/diabetes-readmission
EN/PT
← todos os projetos · machine learning · regressão logística · avaliação de modelos

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?

Regressão logísticascikit-learnLightGBMstatsmodelsNumPyHugging Facepytest
99.340
internações · 69.987 pacientes
11,4%
readmitidos em até 30 dias
94%
do ganho do boosting sobre o acaso, mantido pela RL
40+
métricas por modelo · ICs por paciente
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
00 · resumo

Em poucas palavras

01 · problema

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.

irregularidadeevidênciao que foi feito
alvo raro e fraco11,4% readmitidos em < 30 dias; melhor AUC ≈ 0,68regras de escore próprias, PR AUC, calibração; limiares escolhidos fora do fold
óbitos e hospice2.423 internações não podem ser readmitidasremovidas — senão morrer parece “proteger”
pacientes repetidos69.987 pacientes; 46% das internações de reincidentesdivisão, ajuste e bootstrap por paciente
ausência massivapeso 97% · glicose 95% · HbA1c 83% · especialidade 49% · pagador 40%peso descartado; “não medido” mantido como nível
códigos de alta cardinalidade716 diagnósticos CID-9 primários · 72 especialidades9 capítulos do CID-9; 12 especialidades principais; níveis raros agrupados por fold
caudas pesadasinternações prévias 0–21 · idas ao PS 0–76log1p + B-splines cúbicos dentro do pipeline
IDs guardados como númerosadmissão / alta / origem são códigos nominaismapeados 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.

02 · validação

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:

verificação de vazamento · CV de 5 folds nos pacientes de treinoROC AUC
CV, divisão aleatória por internaçãoCV, divisão por pacientepacientes do teste
0,600,620,640,660,680,70RL · log + splines (principal) · CV, divisão aleatória por internação: 0,6610,661RL · log + splines (principal) · CV, divisão por paciente: 0,6610,661RL · log + splines (principal) · pacientes do teste: 0,6700,670RL · log + splines (principal)LightGBM · CV, divisão aleatória por internação: 0,6730,673LightGBM · CV, divisão por paciente: 0,6740,674LightGBM · pacientes do teste: 0,6810,681LightGBMFloresta aleatória · CV, divisão aleatória por internação: 0,6710,671Floresta aleatória · CV, divisão por paciente: 0,6700,670Floresta aleatória · pacientes do teste: 0,6760,676Floresta aleatóriaFloresta, folhas de tamanho 1 · CV, divisão aleatória por internação: 0,6520,652Floresta, folhas de tamanho 1 · CV, divisão por paciente: 0,6510,651Floresta, folhas de tamanho 1 · pacientes do teste: 0,6610,661Floresta, folhas de tamanho 1
AUC ROC média nos 5 folds sobre as 79.567 internações de treino; terceira barra: conjunto de teste. Fonte: results/results.json (leakage).

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.

03 · modelos

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.

modeloo que éhiperparâmetros escolhidoslog loss (CV)
RL · log + splines (principal)log1p(contagens) → B-splines cúbicos, one-hot nas categóricas, L2C=0,0100,3380
RL · splines + L1/L2mesmas variáveis, penalização elastic net (solver saga)C=0,100, l1_ratio=1,0000,3378
RL · termos linearescontagens brutas padronizadas, one-hot, L2C=0,0100,3383
RL · splines + class_weightRL principal com class_weight=“balanced”C=0,0100,6490
LightGBMgradient boosting, busca aleatória com 30 configuraçõessubsample_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,8000,3337
Floresta aleatória400 árvores, grade de 6 configuraçõesmax_features=0,300, min_samples_leaf=200,3345
RL · só internações préviasuma 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ê.

04 · comparação

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.

AUC ROC · pacientes de teste · IC 95% por bootstrap de pacientesn = 19.773
0,580,600,620,640,660,680,70LightGBMLightGBM: 0,681 [0,668; 0,693]0,681Floresta aleatóriaFloresta aleatória: 0,676 [0,663; 0,690]0,676RL · splines + L1/L2RL · splines + L1/L2: 0,671 [0,658; 0,684]0,671RL · splines + class_weightRL · splines + class_weight: 0,670 [0,656; 0,683]0,670RL · log + splines (principal)RL · log + splines (principal): 0,670 [0,656; 0,683]0,670RL · termos linearesRL · termos lineares: 0,670 [0,656; 0,683]0,670RL · só internações préviasRL · só internações prévias: 0,611 [0,597; 0,627]0,611
B = 1.000 reamostragens de pacientes (não de internações). Fonte: results/results.json (test, ci).

Métricas de ordenação (sem limiar)

modeloAUC ROCIC 95%GiniKSPR AUClift PRsensib. nos 10% de maior riscosensib. nos 20% de maior riscolift nos 10% de maior risco
RL · log + splines (principal)0,670[0,656; 0,683]0,3400,2490,2181,93×23,0%38,8%2,30×
RL · splines + L1/L20,671[0,658; 0,684]0,3430,2530,2191,93×22,8%39,0%2,28×
RL · termos lineares0,670[0,656; 0,683]0,3400,2460,2221,96×22,7%38,9%2,27×
RL · splines + class_weight0,670[0,656; 0,683]0,3400,2480,2171,91×22,8%38,9%2,28×
LightGBM0,681[0,668; 0,693]0,3610,2590,2422,13×25,5%40,3%2,55×
Floresta aleatória0,676[0,663; 0,690]0,3530,2590,2392,10×24,0%40,6%2,40×
RL · só internações prévias0,611[0,597; 0,627]0,2230,1910,1841,63×21,3%35,1%2,13×
Só a prevalência0,500—0,0000,0000,1131,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)

modeloBrierIC 95%ganho no Brierlog lossganho na log lossinclinação de discriminação
RL · log + splines (principal)0,0962[0,0925; 0,0997]4,4%0,33475,4%0,043
RL · splines + L1/L20,0962[0,0925; 0,0997]4,4%0,33455,4%0,044
RL · termos lineares0,0961[0,0924; 0,0996]4,4%0,33485,4%0,043
RL · splines + class_weight0,2254[0,2232; 0,2276]-124,1%0,6453-82,4%0,086
LightGBM0,0950[0,0914; 0,0985]5,6%0,33056,6%0,051
Floresta aleatória0,0953[0,0917; 0,0988]5,2%0,33166,2%0,047
RL · só internações prévias0,0973[0,0935; 0,1010]3,3%0,34163,4%0,031
Só a prevalência0,1006—0,0%0,35370,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 lossveredito (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

modelocoeficienteslog loss (CV)AUC ROC (teste)Δ AUC vs RL · splinesΔ AUC vs LightGBMPR AUCBrierinclinação de cal.
RL · log + splines (principal)2010,33800,670—−0,0110,2180,09621,04
RL · splines + CID-9 de 3 dígitos5170,33730,673+0,003
[0,000; 0,006]
−0,008
[-0,014; -0,002]
0,2200,09601,04
RL · splines + interações2510,33740,671+0,001
[-0,001; 0,004]
−0,010
[-0,014; -0,005]
0,2260,09591,03
RL · splines + CID-9 + interações5670,33670,674+0,004
[0,001; 0,007]
−0,007
[-0,012; -0,002]
0,2280,09571,03
LightGBM—0,33370,681+0,011—0,2420,09501,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.

05 · limiares

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τsinalizadosacuráciaacur. bal.precisãosensibilidadeespecificidadeVPNF1F2MCCκRV+RV−DOR
RL · log + splines (principal)0,13126,1%0,7330,6200,2060,4750,7660,9190,2870,3760,1740,1532,030,692,95
RL · splines + L1/L20,13225,6%0,7370,6190,2070,4670,7710,9190,2870,3740,1740,1542,040,692,96
RL · termos lineares0,13025,2%0,7360,6110,2020,4500,7730,9170,2790,3620,1630,1451,980,712,78
RL · splines + class_weight0,53826,8%0,7260,6170,2020,4760,7590,9190,2830,3740,1680,1471,970,692,85
LightGBM0,14024,1%0,7510,6260,2190,4640,7880,9200,2970,3790,1870,1692,190,683,21
Floresta aleatória0,13827,0%0,7270,6210,2040,4850,7580,9200,2870,3800,1740,1522,000,682,95
RL · só internações prévias0,11932,8%0,6720,5960,1720,4970,6940,9150,2560,3610,1290,1051,620,722,24

τ maximiza o F1 nas predições out-of-fold de cada modelo. Teste, n = 19.773.

modeloτsinalizadosacuráciaacur. bal.precisãosensibilidadeespecificidadeVPNF1F2MCCκRV+RV−DOR
RL · log + splines (principal)0,11037,6%0,6450,6230,1790,5940,6510,9260,2750,4060,1600,1221,700,622,73
RL · splines + L1/L20,11037,1%0,6490,6230,1800,5900,6570,9260,2760,4060,1620,1241,720,622,76
RL · termos lineares0,10641,2%0,6170,6210,1730,6270,6150,9280,2710,4110,1560,1131,630,612,69
RL · splines + class_weight0,49236,8%0,6510,6220,1800,5860,6590,9260,2760,4040,1610,1241,720,632,73
LightGBM0,11536,2%0,6570,6240,1830,5830,6660,9260,2780,4050,1640,1271,750,632,79
Floresta aleatória0,11638,8%0,6380,6290,1800,6160,6410,9290,2790,4150,1670,1251,720,602,86
RL · só internações prévias0,11932,8%0,6720,5960,1720,4970,6940,9150,2560,3610,1290,1051,620,722,24

τ maximiza sensibilidade + especificidade − 1 fora do fold: mais sinalizações, sensibilidade maior, precisão menor.

modeloτsinalizadosacuráciaacur. bal.precisãosensibilidadeespecificidadeVPNF1F2MCCκRV+RV−DOR
RL · log + splines (principal)0,14719,9%0,7750,6050,2200,3850,8250,9130,2800,3350,1670,1582,200,752,95
RL · splines + L1/L20,14820,1%0,7750,6070,2210,3910,8240,9140,2820,3390,1700,1612,220,743,00
RL · termos lineares0,14119,7%0,7760,6050,2210,3840,8260,9130,2800,3340,1670,1592,210,752,96
RL · splines + class_weight0,57819,9%0,7760,6070,2210,3890,8250,9130,2820,3380,1700,1612,220,743,00
LightGBM0,15220,1%0,7770,6150,2280,4040,8250,9150,2920,3500,1810,1712,310,723,20
Floresta aleatória0,15719,8%0,7800,6160,2310,4040,8280,9160,2940,3520,1850,1752,350,723,27
RL · só internações prévias0,12013,8%0,8110,5780,2280,2770,8800,9050,2500,2650,1440,1432,300,822,80

τ = percentil 80 dos escores out-of-fold: um orçamento fixo de acompanhamento para 20% das altas.

modeloτsinalizadosacuráciaacur. bal.precisãosensibilidadeespecificidadeVPNF1F2MCCκRV+RV−DOR
RL · log + splines (principal)0,5000,2%0,8870,5040,5410,0090,9990,8870,0180,0110,0580,0149,190,999,26
RL · splines + L1/L20,5000,2%0,8870,5040,5120,0090,9990,8870,0180,0120,0570,0148,200,998,27
RL · termos lineares0,5000,4%0,8870,5090,6290,0200,9990,8880,0380,0240,0970,03113,220,9813,46
RL · splines + class_weight0,50034,9%0,6650,6210,1830,5650,6780,9240,2770,3990,1620,1271,760,642,73
LightGBM0,5000,2%0,8870,5050,6670,0110,9990,8880,0210,0130,0740,01815,620,9915,78
Floresta aleatória0,5000,0%0,8870,500—0,0001,0000,8870,0000,0000,0000,000—1,00—
RL · só internações prévias0,5000,3%0,8880,5090,6890,0190,9990,8880,0360,0230,1010,03117,270,9817,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.

06 · calibração

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:

diagrama de confiabilidade · decis de risco · pacientes de testeobservado vs previsto
RL · log + splines (principal)LightGBMRL · splines + class_weightcalibração perfeita
0,00,10,20,30,00,10,20,30,40,50,60,70,8RL · splines + class_weight: x = 0,273 · y = 0,042RL · splines + class_weight: x = 0,333 · y = 0,052RL · splines + class_weight: x = 0,367 · y = 0,070RL · splines + class_weight: x = 0,397 · y = 0,082RL · splines + class_weight: x = 0,428 · y = 0,082RL · splines + class_weight: x = 0,461 · y = 0,104RL · splines + class_weight: x = 0,500 · y = 0,121RL · splines + class_weight: x = 0,548 · y = 0,140RL · splines + class_weight: x = 0,613 · y = 0,182RL · splines + class_weight: x = 0,736 · y = 0,259LightGBM: x = 0,042 · y = 0,037LightGBM: x = 0,056 · y = 0,056LightGBM: x = 0,067 · y = 0,064LightGBM: x = 0,079 · y = 0,073LightGBM: x = 0,090 · y = 0,096LightGBM: x = 0,103 · y = 0,109LightGBM: x = 0,117 · y = 0,103LightGBM: x = 0,138 · y = 0,141LightGBM: x = 0,171 · y = 0,168LightGBM: x = 0,269 · y = 0,290RL · log + splines (principal): x = 0,050 · y = 0,043RL · log + splines (principal): x = 0,064 · y = 0,054RL · log + splines (principal): x = 0,072 · y = 0,066RL · log + splines (principal): x = 0,081 · y = 0,083RL · log + splines (principal): x = 0,090 · y = 0,084RL · log + splines (principal): x = 0,100 · y = 0,107RL · log + splines (principal): x = 0,114 · y = 0,111RL · log + splines (principal): x = 0,134 · y = 0,147RL · log + splines (principal): x = 0,166 · y = 0,180RL · log + splines (principal): x = 0,264 · y = 0,261
Cada ponto é um decil de risco previsto (≈ 1.977 internações). Fonte: results/results.json (reliability).
modelop̂ médioO/EinterceptoinclinaçãoECEMCEz de SpiegelhalterHL χ²(8)p de HL
RL · log + splines (principal)0,1141,00-0,0011,0430,00700,0133-0,1414,200,077
RL · splines + L1/L20,1141,00-0,0041,0390,00840,0171-0,2418,800,016
RL · termos lineares0,1141,00-0,0021,0830,00900,0268-0,2535,92< 0,001
RL · splines + class_weight0,4660,24-2,0530,9740,35220,4769-6,0511.113,66< 0,001
LightGBM0,1131,000,0031,0820,00670,0205-0,4312,520,129
Floresta aleatória0,1141,00-0,0041,0860,00680,0145-0,8113,000,112
RL · só internações prévias0,1131,000,0021,1010,01110,0268-0,1131,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.

07 · inferência

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:

odds ratios · IC 95% com EP clusterizado por paciente · escala logn = 79.567 · p = 68
aumenta a chancereduz a chance
0,500,751,001,502,00alta para reabilitaçãoOR 3,68 [3,24; 4,18]3,68alta para outra internaçãoOR 2,01 [1,81; 2,22]2,01alta para casa de repouso (SNF/ICF)OR 1,50 [1,40; 1,61]1,50internações no ano anterior (por 1)OR 1,30 [1,28; 1,32]1,30dose de insulina reduzidaOR 1,27 [1,16; 1,40]1,27alta para casa + atendimento domiciliarOR 1,18 [1,10; 1,27]1,18diagnósticos (por 1)OR 1,04 [1,03; 1,06]1,04pagador: MedicareOR 0,86 [0,80; 0,91]0,86sem medicação para diabetesOR 0,85 [0,79; 0,91]0,85diagnóstico principal respiratórioOR 0,82 [0,75; 0,89]0,82especialidade: cardiologiaOR 0,77 [0,68; 0,87]0,77
Referências: alta para casa, admissão pelo PS, diagnóstico principal circulatório, HbA1c não medida, sem insulina, pagador ausente, especialidade ausente. Fonte: results/results.json (inference).
  • 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.

08 · decisões

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.

curva de decisão · pacientes de testebenefício líquido vs limiar
RL · log + splines (principal)LightGBMtratar todostratar ninguém
0,000,010,020,030,040,050,060,070,080,090,050,100,150,200,250,300,350,40
Benefício líquido = VP/n − FP/n · τ/(1 − τ) (Vickers & Elkin, 2006). Fonte: results/results.json (dca).

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.

curva de aprendizado · AUC de teste vs tamanho do treino (pacientes subamostrados)ROC AUC
RL · log + splines (principal)LightGBM
0,6000,6250,6500,6750,7001.6103.9667.92019.85439.80979.567LightGBM: x = 1.610 · y = 0,618LightGBM: x = 3.966 · y = 0,618LightGBM: x = 7.920 · y = 0,643LightGBM: x = 19.854 · y = 0,661LightGBM: x = 39.809 · y = 0,678LightGBM: x = 79.567 · y = 0,681RL · log + splines (principal): x = 1.610 · y = 0,624RL · log + splines (principal): x = 3.966 · y = 0,633RL · log + splines (principal): x = 7.920 · y = 0,648RL · log + splines (principal): x = 19.854 · y = 0,658RL · log + splines (principal): x = 39.809 · y = 0,667RL · log + splines (principal): x = 79.567 · y = 0,670
Mesmo conjunto de teste; hiperparâmetros fixados nos valores escolhidos com todos os dados. Com até 8 mil internações a RL vence; o boosting passa à frente perto de 20 mil. Fonte: results/results.json (learning_curve).

Subgrupos (RL principal, pacientes de teste)

variávelgrupontaxa observadamédia previstaAUC ROC
idade70+8.75211,7%12,3%0,631
idade50–697.82311,3%10,7%0,692
idade<503.19810,6%10,3%0,708
raçabranca14.81311,7%11,5%0,667
raçaafro-americana3.69710,8%11,5%0,669
raçaausente4477,2%9,6%0,638
raçahispânica3989,0%10,4%0,748
raçaoutra30210,3%9,7%0,681
sexofeminino10.72611,4%11,5%0,674
sexomasculino9.04711,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.

09 · entrega

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.