EWP course ‘Prognostic Research’:

El GUSTO-I fue un ensayo clínico internacional, multicéntrico, aleatorizado, diseñado para comparar diferentes estrategias trombolíticas en pacientes con infarto agudo de miocardio con elevación del ST (IAMCEST). Su objetivo principal era determinar cuál tratamiento trombolítico lograba mejorar la supervivencia a 30 días.

assignment for practical GUSTO-I data

## Warning: package 'readxl' was built under R version 4.4.3
## Warning: package 'dplyr' was built under R version 4.4.3
## 
## Adjuntando el paquete: 'dplyr'
## The following objects are masked from 'package:stats':
## 
##     filter, lag
## The following objects are masked from 'package:base':
## 
##     intersect, setdiff, setequal, union
## Warning: package 'summarytools' was built under R version 4.4.3
## Warning: package 'epiDisplay' was built under R version 4.4.3
## Cargando paquete requerido: foreign
## Cargando paquete requerido: survival
## Cargando paquete requerido: MASS
## Warning: package 'MASS' was built under R version 4.4.3
## 
## Adjuntando el paquete: 'MASS'
## The following object is masked from 'package:dplyr':
## 
##     select
## Cargando paquete requerido: nnet
## 
## Adjuntando el paquete: 'gmodels'
## The following object is masked from 'package:epiDisplay':
## 
##     ci

Question 1: Descriptives and univariable analysis

Give some descriptives of the covariables.

Data Frame Summary

df

Dimensions: 785 x 26
Duplicates: 0
No Variable Stats / Values Freqs (% of Valid) Graph Valid Missing
1 day30 [numeric]
Min : 0
Mean : 0.1
Max : 1
0:733(93.4%)
1:52(6.6%)
785 (100.0%) 0 (0.0%)
2 sex [numeric]
Min : 0
Mean : 0.3
Max : 1
0:582(74.1%)
1:203(25.9%)
785 (100.0%) 0 (0.0%)
3 age [numeric]
Mean (sd) : 61.8 (11.1)
min ≤ med ≤ max:
28.4 ≤ 62.8 ≤ 86
IQR (CV) : 17.2 (0.2)
710 distinct values 785 (100.0%) 0 (0.0%)
4 a65 [numeric]
Min : 0
Mean : 0.4
Max : 1
0:458(58.3%)
1:327(41.7%)
785 (100.0%) 0 (0.0%)
5 killip [numeric]
Mean (sd) : 1.2 (0.5)
min ≤ med ≤ max:
1 ≤ 1 ≤ 4
IQR (CV) : 0 (0.4)
1:616(78.5%)
2:148(18.9%)
3:20(2.5%)
4:1(0.1%)
785 (100.0%) 0 (0.0%)
6 sho [numeric]
Min : 0
Mean : 0
Max : 1
0:764(97.3%)
1:21(2.7%)
785 (100.0%) 0 (0.0%)
7 dia [numeric]
Min : 0
Mean : 0.1
Max : 1
0:700(89.2%)
1:85(10.8%)
785 (100.0%) 0 (0.0%)
8 hyp [numeric]
Min : 0
Mean : 0.1
Max : 1
0:745(94.9%)
1:40(5.1%)
785 (100.0%) 0 (0.0%)
9 hrt [numeric]
Min : 0
Mean : 0.3
Max : 1
0:576(73.4%)
1:209(26.6%)
785 (100.0%) 0 (0.0%)
10 ant [numeric]
Min : 0
Mean : 0.4
Max : 1
0:506(64.5%)
1:279(35.5%)
785 (100.0%) 0 (0.0%)
11 pmi [numeric]
Min : 0
Mean : 0.2
Max : 1
0:645(82.2%)
1:140(17.8%)
785 (100.0%) 0 (0.0%)
12 hei [numeric]
Mean (sd) : 169.2 (9)
min ≤ med ≤ max:
141.3 ≤ 170 ≤ 197
IQR (CV) : 12 (0.1)
128 distinct values 785 (100.0%) 0 (0.0%)
13 wei [numeric]
Mean (sd) : 75.2 (14)
min ≤ med ≤ max:
40 ≤ 75 ≤ 128
IQR (CV) : 18 (0.2)
111 distinct values 785 (100.0%) 0 (0.0%)
14 htn [numeric]
Min : 0
Mean : 0.4
Max : 1
0:490(62.4%)
1:295(37.6%)
785 (100.0%) 0 (0.0%)
15 smk [numeric]
Mean (sd) : 1.9 (0.8)
min ≤ med ≤ max:
1 ≤ 2 ≤ 3
IQR (CV) : 2 (0.4)
1:262(33.4%)
2:306(39.0%)
3:217(27.6%)
785 (100.0%) 0 (0.0%)
16 lip [numeric]
Min : 0
Mean : 0.4
Max : 1
0:480(61.1%)
1:305(38.9%)
785 (100.0%) 0 (0.0%)
17 pan [numeric]
Min : 0
Mean : 0.4
Max : 1
0:490(62.4%)
1:295(37.6%)
785 (100.0%) 0 (0.0%)
18 fam [numeric]
Min : 0
Mean : 0.4
Max : 1
0:460(58.6%)
1:325(41.4%)
785 (100.0%) 0 (0.0%)
19 ste [numeric]
Mean (sd) : 4.3 (1.8)
min ≤ med ≤ max:
0 ≤ 4 ≤ 10
IQR (CV) : 3 (0.4)
11 distinct values 785 (100.0%) 0 (0.0%)
20 st4 [numeric]
Min : 0
Mean : 0.4
Max : 1
0:460(58.6%)
1:325(41.4%)
785 (100.0%) 0 (0.0%)
21 ttr [numeric]
Min : 0
Mean : 0.5
Max : 1
0:390(49.7%)
1:395(50.3%)
785 (100.0%) 0 (0.0%)
22 esamp [numeric] 1 distinct value
1:785(100.0%)
785 (100.0%) 0 (0.0%)
23 grpl [numeric] 1 distinct value
4:785(100.0%)
785 (100.0%) 0 (0.0%)
24 grps [numeric]
Mean (sd) : 9.9 (0.9)
min ≤ med ≤ max:
9 ≤ 10 ≤ 11
IQR (CV) : 2 (0.1)
9:327(41.7%)
10:195(24.8%)
11:263(33.5%)
785 (100.0%) 0 (0.0%)
25 regl [numeric] 1 distinct value
2:785(100.0%)
785 (100.0%) 0 (0.0%)
26 hig [numeric]
Min : 0
Mean : 0.5
Max : 1
0:421(53.6%)
1:364(46.4%)
785 (100.0%) 0 (0.0%)

Generated by summarytools 1.1.4 (R version 4.4.2)
2025-05-13

En una cohorte de 785 pacientes con infarto agudo de miocardio, la mortalidad a 30 días fue del 6.6%. La edad media fue de 61.8 años, con un 41.7% de pacientes mayores de 65 años. La mayoría eran hombres (74.1%). La clase Killip fue mayor o igual a II en el 21.5% de los casos, y el 2.7% presentó shock cardiogénico. Un 10.8% tenía diagnóstico de diabetes y el 5.1% presentó hipotensión (presión sistólica < 100 mmHg). Asimismo, el 26.6% presentó taquicardia (FC > 80 lpm), y un 35.5% tuvo infarto anterior. Respecto a factores de riesgo cardiovascular, el 37.6% tenía hipertensión, el 38.9% dislipidemia, y el 39% eran exfumadores, mientras que el 27.6% eran fumadores activos. Finalmente, el 50.3% presentó un tiempo de alivio del dolor torácico superior a una hora y el 41.4% mostró elevación del ST en más de cuatro derivaciones, lo cual puede reflejar una mayor extensión del daño miocárdico.

Study some cross tables: outcome*predictor.

## 
## ============================
## Tabla: day30 * sex 
## ============================
## 
##  
##    Cell Contents
## |-------------------------|
## |                       N |
## |           N / Row Total |
## |         N / Table Total |
## |-------------------------|
## 
##  
## Total Observations in Table:  785 
## 
##  
##                       | sub_df[[var]] 
## sub_df[[outcome_var]] |         0 |         1 | Row Total | 
## ----------------------|-----------|-----------|-----------|
##                     0 |       548 |       185 |       733 | 
##                       |     0.748 |     0.252 |     0.934 | 
##                       |     0.698 |     0.236 |           | 
## ----------------------|-----------|-----------|-----------|
##                     1 |        34 |        18 |        52 | 
##                       |     0.654 |     0.346 |     0.066 | 
##                       |     0.043 |     0.023 |           | 
## ----------------------|-----------|-----------|-----------|
##          Column Total |       582 |       203 |       785 | 
## ----------------------|-----------|-----------|-----------|
## 
##  
## 
## ============================
## Tabla: day30 * a65 
## ============================
## 
##  
##    Cell Contents
## |-------------------------|
## |                       N |
## |           N / Row Total |
## |         N / Table Total |
## |-------------------------|
## 
##  
## Total Observations in Table:  785 
## 
##  
##                       | sub_df[[var]] 
## sub_df[[outcome_var]] |         0 |         1 | Row Total | 
## ----------------------|-----------|-----------|-----------|
##                     0 |       446 |       287 |       733 | 
##                       |     0.608 |     0.392 |     0.934 | 
##                       |     0.568 |     0.366 |           | 
## ----------------------|-----------|-----------|-----------|
##                     1 |        12 |        40 |        52 | 
##                       |     0.231 |     0.769 |     0.066 | 
##                       |     0.015 |     0.051 |           | 
## ----------------------|-----------|-----------|-----------|
##          Column Total |       458 |       327 |       785 | 
## ----------------------|-----------|-----------|-----------|
## 
##  
## 
## ============================
## Tabla: day30 * killip 
## ============================
## 
##  
##    Cell Contents
## |-------------------------|
## |                       N |
## |           N / Row Total |
## |         N / Table Total |
## |-------------------------|
## 
##  
## Total Observations in Table:  785 
## 
##  
##                       | sub_df[[var]] 
## sub_df[[outcome_var]] |         1 |         2 |         3 |         4 | Row Total | 
## ----------------------|-----------|-----------|-----------|-----------|-----------|
##                     0 |       589 |       130 |        14 |         0 |       733 | 
##                       |     0.804 |     0.177 |     0.019 |     0.000 |     0.934 | 
##                       |     0.750 |     0.166 |     0.018 |     0.000 |           | 
## ----------------------|-----------|-----------|-----------|-----------|-----------|
##                     1 |        27 |        18 |         6 |         1 |        52 | 
##                       |     0.519 |     0.346 |     0.115 |     0.019 |     0.066 | 
##                       |     0.034 |     0.023 |     0.008 |     0.001 |           | 
## ----------------------|-----------|-----------|-----------|-----------|-----------|
##          Column Total |       616 |       148 |        20 |         1 |       785 | 
## ----------------------|-----------|-----------|-----------|-----------|-----------|
## 
##  
## 
## ============================
## Tabla: day30 * sho 
## ============================
## 
##  
##    Cell Contents
## |-------------------------|
## |                       N |
## |           N / Row Total |
## |         N / Table Total |
## |-------------------------|
## 
##  
## Total Observations in Table:  785 
## 
##  
##                       | sub_df[[var]] 
## sub_df[[outcome_var]] |         0 |         1 | Row Total | 
## ----------------------|-----------|-----------|-----------|
##                     0 |       719 |        14 |       733 | 
##                       |     0.981 |     0.019 |     0.934 | 
##                       |     0.916 |     0.018 |           | 
## ----------------------|-----------|-----------|-----------|
##                     1 |        45 |         7 |        52 | 
##                       |     0.865 |     0.135 |     0.066 | 
##                       |     0.057 |     0.009 |           | 
## ----------------------|-----------|-----------|-----------|
##          Column Total |       764 |        21 |       785 | 
## ----------------------|-----------|-----------|-----------|
## 
##  
## 
## ============================
## Tabla: day30 * dia 
## ============================
## 
##  
##    Cell Contents
## |-------------------------|
## |                       N |
## |           N / Row Total |
## |         N / Table Total |
## |-------------------------|
## 
##  
## Total Observations in Table:  785 
## 
##  
##                       | sub_df[[var]] 
## sub_df[[outcome_var]] |         0 |         1 | Row Total | 
## ----------------------|-----------|-----------|-----------|
##                     0 |       657 |        76 |       733 | 
##                       |     0.896 |     0.104 |     0.934 | 
##                       |     0.837 |     0.097 |           | 
## ----------------------|-----------|-----------|-----------|
##                     1 |        43 |         9 |        52 | 
##                       |     0.827 |     0.173 |     0.066 | 
##                       |     0.055 |     0.011 |           | 
## ----------------------|-----------|-----------|-----------|
##          Column Total |       700 |        85 |       785 | 
## ----------------------|-----------|-----------|-----------|
## 
##  
## 
## ============================
## Tabla: day30 * hyp 
## ============================
## 
##  
##    Cell Contents
## |-------------------------|
## |                       N |
## |           N / Row Total |
## |         N / Table Total |
## |-------------------------|
## 
##  
## Total Observations in Table:  785 
## 
##  
##                       | sub_df[[var]] 
## sub_df[[outcome_var]] |         0 |         1 | Row Total | 
## ----------------------|-----------|-----------|-----------|
##                     0 |       698 |        35 |       733 | 
##                       |     0.952 |     0.048 |     0.934 | 
##                       |     0.889 |     0.045 |           | 
## ----------------------|-----------|-----------|-----------|
##                     1 |        47 |         5 |        52 | 
##                       |     0.904 |     0.096 |     0.066 | 
##                       |     0.060 |     0.006 |           | 
## ----------------------|-----------|-----------|-----------|
##          Column Total |       745 |        40 |       785 | 
## ----------------------|-----------|-----------|-----------|
## 
##  
## 
## ============================
## Tabla: day30 * hrt 
## ============================
## 
##  
##    Cell Contents
## |-------------------------|
## |                       N |
## |           N / Row Total |
## |         N / Table Total |
## |-------------------------|
## 
##  
## Total Observations in Table:  785 
## 
##  
##                       | sub_df[[var]] 
## sub_df[[outcome_var]] |         0 |         1 | Row Total | 
## ----------------------|-----------|-----------|-----------|
##                     0 |       551 |       182 |       733 | 
##                       |     0.752 |     0.248 |     0.934 | 
##                       |     0.702 |     0.232 |           | 
## ----------------------|-----------|-----------|-----------|
##                     1 |        25 |        27 |        52 | 
##                       |     0.481 |     0.519 |     0.066 | 
##                       |     0.032 |     0.034 |           | 
## ----------------------|-----------|-----------|-----------|
##          Column Total |       576 |       209 |       785 | 
## ----------------------|-----------|-----------|-----------|
## 
##  
## 
## ============================
## Tabla: day30 * ant 
## ============================
## 
##  
##    Cell Contents
## |-------------------------|
## |                       N |
## |           N / Row Total |
## |         N / Table Total |
## |-------------------------|
## 
##  
## Total Observations in Table:  785 
## 
##  
##                       | sub_df[[var]] 
## sub_df[[outcome_var]] |         0 |         1 | Row Total | 
## ----------------------|-----------|-----------|-----------|
##                     0 |       480 |       253 |       733 | 
##                       |     0.655 |     0.345 |     0.934 | 
##                       |     0.611 |     0.322 |           | 
## ----------------------|-----------|-----------|-----------|
##                     1 |        26 |        26 |        52 | 
##                       |     0.500 |     0.500 |     0.066 | 
##                       |     0.033 |     0.033 |           | 
## ----------------------|-----------|-----------|-----------|
##          Column Total |       506 |       279 |       785 | 
## ----------------------|-----------|-----------|-----------|
## 
##  
## 
## ============================
## Tabla: day30 * pmi 
## ============================
## 
##  
##    Cell Contents
## |-------------------------|
## |                       N |
## |           N / Row Total |
## |         N / Table Total |
## |-------------------------|
## 
##  
## Total Observations in Table:  785 
## 
##  
##                       | sub_df[[var]] 
## sub_df[[outcome_var]] |         0 |         1 | Row Total | 
## ----------------------|-----------|-----------|-----------|
##                     0 |       612 |       121 |       733 | 
##                       |     0.835 |     0.165 |     0.934 | 
##                       |     0.780 |     0.154 |           | 
## ----------------------|-----------|-----------|-----------|
##                     1 |        33 |        19 |        52 | 
##                       |     0.635 |     0.365 |     0.066 | 
##                       |     0.042 |     0.024 |           | 
## ----------------------|-----------|-----------|-----------|
##          Column Total |       645 |       140 |       785 | 
## ----------------------|-----------|-----------|-----------|
## 
##  
## 
## ============================
## Tabla: day30 * htn 
## ============================
## 
##  
##    Cell Contents
## |-------------------------|
## |                       N |
## |           N / Row Total |
## |         N / Table Total |
## |-------------------------|
## 
##  
## Total Observations in Table:  785 
## 
##  
##                       | sub_df[[var]] 
## sub_df[[outcome_var]] |         0 |         1 | Row Total | 
## ----------------------|-----------|-----------|-----------|
##                     0 |       463 |       270 |       733 | 
##                       |     0.632 |     0.368 |     0.934 | 
##                       |     0.590 |     0.344 |           | 
## ----------------------|-----------|-----------|-----------|
##                     1 |        27 |        25 |        52 | 
##                       |     0.519 |     0.481 |     0.066 | 
##                       |     0.034 |     0.032 |           | 
## ----------------------|-----------|-----------|-----------|
##          Column Total |       490 |       295 |       785 | 
## ----------------------|-----------|-----------|-----------|
## 
##  
## 
## ============================
## Tabla: day30 * lip 
## ============================
## 
##  
##    Cell Contents
## |-------------------------|
## |                       N |
## |           N / Row Total |
## |         N / Table Total |
## |-------------------------|
## 
##  
## Total Observations in Table:  785 
## 
##  
##                       | sub_df[[var]] 
## sub_df[[outcome_var]] |         0 |         1 | Row Total | 
## ----------------------|-----------|-----------|-----------|
##                     0 |       446 |       287 |       733 | 
##                       |     0.608 |     0.392 |     0.934 | 
##                       |     0.568 |     0.366 |           | 
## ----------------------|-----------|-----------|-----------|
##                     1 |        34 |        18 |        52 | 
##                       |     0.654 |     0.346 |     0.066 | 
##                       |     0.043 |     0.023 |           | 
## ----------------------|-----------|-----------|-----------|
##          Column Total |       480 |       305 |       785 | 
## ----------------------|-----------|-----------|-----------|
## 
##  
## 
## ============================
## Tabla: day30 * pan 
## ============================
## 
##  
##    Cell Contents
## |-------------------------|
## |                       N |
## |           N / Row Total |
## |         N / Table Total |
## |-------------------------|
## 
##  
## Total Observations in Table:  785 
## 
##  
##                       | sub_df[[var]] 
## sub_df[[outcome_var]] |         0 |         1 | Row Total | 
## ----------------------|-----------|-----------|-----------|
##                     0 |       463 |       270 |       733 | 
##                       |     0.632 |     0.368 |     0.934 | 
##                       |     0.590 |     0.344 |           | 
## ----------------------|-----------|-----------|-----------|
##                     1 |        27 |        25 |        52 | 
##                       |     0.519 |     0.481 |     0.066 | 
##                       |     0.034 |     0.032 |           | 
## ----------------------|-----------|-----------|-----------|
##          Column Total |       490 |       295 |       785 | 
## ----------------------|-----------|-----------|-----------|
## 
##  
## 
## ============================
## Tabla: day30 * fam 
## ============================
## 
##  
##    Cell Contents
## |-------------------------|
## |                       N |
## |           N / Row Total |
## |         N / Table Total |
## |-------------------------|
## 
##  
## Total Observations in Table:  785 
## 
##  
##                       | sub_df[[var]] 
## sub_df[[outcome_var]] |         0 |         1 | Row Total | 
## ----------------------|-----------|-----------|-----------|
##                     0 |       426 |       307 |       733 | 
##                       |     0.581 |     0.419 |     0.934 | 
##                       |     0.543 |     0.391 |           | 
## ----------------------|-----------|-----------|-----------|
##                     1 |        34 |        18 |        52 | 
##                       |     0.654 |     0.346 |     0.066 | 
##                       |     0.043 |     0.023 |           | 
## ----------------------|-----------|-----------|-----------|
##          Column Total |       460 |       325 |       785 | 
## ----------------------|-----------|-----------|-----------|
## 
##  
## 
## ============================
## Tabla: day30 * st4 
## ============================
## 
##  
##    Cell Contents
## |-------------------------|
## |                       N |
## |           N / Row Total |
## |         N / Table Total |
## |-------------------------|
## 
##  
## Total Observations in Table:  785 
## 
##  
##                       | sub_df[[var]] 
## sub_df[[outcome_var]] |         0 |         1 | Row Total | 
## ----------------------|-----------|-----------|-----------|
##                     0 |       434 |       299 |       733 | 
##                       |     0.592 |     0.408 |     0.934 | 
##                       |     0.553 |     0.381 |           | 
## ----------------------|-----------|-----------|-----------|
##                     1 |        26 |        26 |        52 | 
##                       |     0.500 |     0.500 |     0.066 | 
##                       |     0.033 |     0.033 |           | 
## ----------------------|-----------|-----------|-----------|
##          Column Total |       460 |       325 |       785 | 
## ----------------------|-----------|-----------|-----------|
## 
##  
## 
## ============================
## Tabla: day30 * ttr 
## ============================
## 
##  
##    Cell Contents
## |-------------------------|
## |                       N |
## |           N / Row Total |
## |         N / Table Total |
## |-------------------------|
## 
##  
## Total Observations in Table:  785 
## 
##  
##                       | sub_df[[var]] 
## sub_df[[outcome_var]] |         0 |         1 | Row Total | 
## ----------------------|-----------|-----------|-----------|
##                     0 |       372 |       361 |       733 | 
##                       |     0.508 |     0.492 |     0.934 | 
##                       |     0.474 |     0.460 |           | 
## ----------------------|-----------|-----------|-----------|
##                     1 |        18 |        34 |        52 | 
##                       |     0.346 |     0.654 |     0.066 | 
##                       |     0.023 |     0.043 |           | 
## ----------------------|-----------|-----------|-----------|
##          Column Total |       390 |       395 |       785 | 
## ----------------------|-----------|-----------|-----------|
## 
## 

What are the univariable relationships between the predictors and the outcome (DAY30)?

# Regresión logística univariada para cada predictor
glm1 <- glm(day30 ~ sex, data = df, family = binomial)
summary(glm1)
## 
## Call:
## glm(formula = day30 ~ sex, family = binomial, data = df)
## 
## Coefficients:
##             Estimate Std. Error z value Pr(>|z|)    
## (Intercept)  -2.7799     0.1767 -15.729   <2e-16 ***
## sex           0.4499     0.3036   1.482    0.138    
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## (Dispersion parameter for binomial family taken to be 1)
## 
##     Null deviance: 382.78  on 784  degrees of freedom
## Residual deviance: 380.68  on 783  degrees of freedom
## AIC: 384.68
## 
## Number of Fisher Scoring iterations: 5
glm2 <- glm(day30 ~ age, data = df, family = binomial)
summary(glm2)
## 
## Call:
## glm(formula = day30 ~ age, family = binomial, data = df)
## 
## Coefficients:
##             Estimate Std. Error z value Pr(>|z|)    
## (Intercept) -9.73920    1.24722  -7.809 5.78e-15 ***
## age          0.10620    0.01749   6.072 1.26e-09 ***
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## (Dispersion parameter for binomial family taken to be 1)
## 
##     Null deviance: 382.78  on 784  degrees of freedom
## Residual deviance: 334.55  on 783  degrees of freedom
## AIC: 338.55
## 
## Number of Fisher Scoring iterations: 6
glm3 <- glm(day30 ~ a65, data = df, family = binomial)
summary(glm3)
## 
## Call:
## glm(formula = day30 ~ a65, family = binomial, data = df)
## 
## Coefficients:
##             Estimate Std. Error z value Pr(>|z|)    
## (Intercept)  -3.6154     0.2925  -12.36  < 2e-16 ***
## a65           1.6448     0.3377    4.87 1.11e-06 ***
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## (Dispersion parameter for binomial family taken to be 1)
## 
##     Null deviance: 382.78  on 784  degrees of freedom
## Residual deviance: 354.07  on 783  degrees of freedom
## AIC: 358.07
## 
## Number of Fisher Scoring iterations: 6
glm4 <- glm(day30 ~ killip, data = df, family = binomial)
summary(glm4)
## 
## Call:
## glm(formula = day30 ~ killip, family = binomial, data = df)
## 
## Coefficients:
##             Estimate Std. Error z value Pr(>|z|)    
## (Intercept)  -4.2655     0.3663 -11.645   <2e-16 ***
## killip        1.1631     0.2157   5.391    7e-08 ***
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## (Dispersion parameter for binomial family taken to be 1)
## 
##     Null deviance: 382.78  on 784  degrees of freedom
## Residual deviance: 356.77  on 783  degrees of freedom
## AIC: 360.77
## 
## Number of Fisher Scoring iterations: 5
glm5 <- glm(day30 ~ sho, data = df, family = binomial)
summary(glm5)
## 
## Call:
## glm(formula = day30 ~ sho, family = binomial, data = df)
## 
## Coefficients:
##             Estimate Std. Error z value Pr(>|z|)    
## (Intercept)  -2.7712     0.1537 -18.034  < 2e-16 ***
## sho           2.0781     0.4877   4.261 2.04e-05 ***
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## (Dispersion parameter for binomial family taken to be 1)
## 
##     Null deviance: 382.78  on 784  degrees of freedom
## Residual deviance: 368.90  on 783  degrees of freedom
## AIC: 372.9
## 
## Number of Fisher Scoring iterations: 5
glm6 <- glm(day30 ~ dia, data = df, family = binomial)
summary(glm6)
## 
## Call:
## glm(formula = day30 ~ dia, family = binomial, data = df)
## 
## Coefficients:
##             Estimate Std. Error z value Pr(>|z|)    
## (Intercept)  -2.7265     0.1574 -17.321   <2e-16 ***
## dia           0.5930     0.3861   1.536    0.125    
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## (Dispersion parameter for binomial family taken to be 1)
## 
##     Null deviance: 382.78  on 784  degrees of freedom
## Residual deviance: 380.66  on 783  degrees of freedom
## AIC: 384.66
## 
## Number of Fisher Scoring iterations: 5
glm7 <- glm(day30 ~ hyp, data = df, family = binomial)
summary(glm7)
## 
## Call:
## glm(formula = day30 ~ hyp, family = binomial, data = df)
## 
## Coefficients:
##             Estimate Std. Error z value Pr(>|z|)    
## (Intercept)  -2.6981     0.1507   -17.9   <2e-16 ***
## hyp           0.7522     0.5013     1.5    0.133    
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## (Dispersion parameter for binomial family taken to be 1)
## 
##     Null deviance: 382.78  on 784  degrees of freedom
## Residual deviance: 380.86  on 783  degrees of freedom
## AIC: 384.86
## 
## Number of Fisher Scoring iterations: 5
glm8 <- glm(day30 ~ hrt, data = df, family = binomial)
summary(glm8)
## 
## Call:
## glm(formula = day30 ~ hrt, family = binomial, data = df)
## 
## Coefficients:
##             Estimate Std. Error z value Pr(>|z|)    
## (Intercept)  -3.0929     0.2045 -15.127  < 2e-16 ***
## hrt           1.1847     0.2904   4.079 4.51e-05 ***
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## (Dispersion parameter for binomial family taken to be 1)
## 
##     Null deviance: 382.78  on 784  degrees of freedom
## Residual deviance: 366.62  on 783  degrees of freedom
## AIC: 370.62
## 
## Number of Fisher Scoring iterations: 5
glm9 <- glm(day30 ~ ant, data = df, family = binomial)
summary(glm9)
## 
## Call:
## glm(formula = day30 ~ ant, family = binomial, data = df)
## 
## Coefficients:
##             Estimate Std. Error z value Pr(>|z|)    
## (Intercept)  -2.9157     0.2013 -14.481   <2e-16 ***
## ant           0.6404     0.2880   2.223   0.0262 *  
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## (Dispersion parameter for binomial family taken to be 1)
## 
##     Null deviance: 382.78  on 784  degrees of freedom
## Residual deviance: 377.90  on 783  degrees of freedom
## AIC: 381.9
## 
## Number of Fisher Scoring iterations: 5
glm10 <- glm(day30 ~ pmi, data = df, family = binomial)
summary(glm10)
## 
## Call:
## glm(formula = day30 ~ pmi, family = binomial, data = df)
## 
## Coefficients:
##             Estimate Std. Error z value Pr(>|z|)    
## (Intercept)  -2.9202     0.1787 -16.341  < 2e-16 ***
## pmi           1.0689     0.3047   3.508 0.000451 ***
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## (Dispersion parameter for binomial family taken to be 1)
## 
##     Null deviance: 382.78  on 784  degrees of freedom
## Residual deviance: 371.67  on 783  degrees of freedom
## AIC: 375.67
## 
## Number of Fisher Scoring iterations: 5
glm11 <- glm(day30 ~ hei, data = df, family = binomial)
summary(glm11)
## 
## Call:
## glm(formula = day30 ~ hei, family = binomial, data = df)
## 
## Coefficients:
##             Estimate Std. Error z value Pr(>|z|)   
## (Intercept)  5.87322    2.57582   2.280  0.02260 * 
## hei         -0.05088    0.01553  -3.277  0.00105 **
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## (Dispersion parameter for binomial family taken to be 1)
## 
##     Null deviance: 382.78  on 784  degrees of freedom
## Residual deviance: 372.13  on 783  degrees of freedom
## AIC: 376.13
## 
## Number of Fisher Scoring iterations: 5
glm12 <- glm(day30 ~ wei, data = df, family = binomial)
summary(glm12)
## 
## Call:
## glm(formula = day30 ~ wei, family = binomial, data = df)
## 
## Coefficients:
##             Estimate Std. Error z value Pr(>|z|)    
## (Intercept)  0.35290    0.78588   0.449 0.653400    
## wei         -0.04171    0.01123  -3.715 0.000203 ***
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## (Dispersion parameter for binomial family taken to be 1)
## 
##     Null deviance: 382.78  on 784  degrees of freedom
## Residual deviance: 368.04  on 783  degrees of freedom
## AIC: 372.04
## 
## Number of Fisher Scoring iterations: 6
glm13 <- glm(day30 ~ htn, data = df, family = binomial)
summary(glm13)
## 
## Call:
## glm(formula = day30 ~ htn, family = binomial, data = df)
## 
## Coefficients:
##             Estimate Std. Error z value Pr(>|z|)    
## (Intercept)  -2.8419     0.1980 -14.355   <2e-16 ***
## htn           0.4623     0.2879   1.606    0.108    
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## (Dispersion parameter for binomial family taken to be 1)
## 
##     Null deviance: 382.78  on 784  degrees of freedom
## Residual deviance: 380.23  on 783  degrees of freedom
## AIC: 384.23
## 
## Number of Fisher Scoring iterations: 5
glm14 <- glm(day30 ~ smk, data = df, family = binomial)
summary(glm14)
## 
## Call:
## glm(formula = day30 ~ smk, family = binomial, data = df)
## 
## Coefficients:
##             Estimate Std. Error z value Pr(>|z|)    
## (Intercept)  -3.5616     0.4339  -8.209 2.23e-16 ***
## smk           0.4446     0.1882   2.363   0.0182 *  
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## (Dispersion parameter for binomial family taken to be 1)
## 
##     Null deviance: 382.78  on 784  degrees of freedom
## Residual deviance: 377.05  on 783  degrees of freedom
## AIC: 381.05
## 
## Number of Fisher Scoring iterations: 5
glm15 <- glm(day30 ~ lip, data = df, family = binomial)
summary(glm15)
## 
## Call:
## glm(formula = day30 ~ lip, family = binomial, data = df)
## 
## Coefficients:
##             Estimate Std. Error z value Pr(>|z|)    
## (Intercept)  -2.5740     0.1779 -14.467   <2e-16 ***
## lip          -0.1952     0.3012  -0.648    0.517    
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## (Dispersion parameter for binomial family taken to be 1)
## 
##     Null deviance: 382.78  on 784  degrees of freedom
## Residual deviance: 382.35  on 783  degrees of freedom
## AIC: 386.35
## 
## Number of Fisher Scoring iterations: 5
glm16 <- glm(day30 ~ pan, data = df, family = binomial)
summary(glm16)
## 
## Call:
## glm(formula = day30 ~ pan, family = binomial, data = df)
## 
## Coefficients:
##             Estimate Std. Error z value Pr(>|z|)    
## (Intercept)  -2.8419     0.1980 -14.355   <2e-16 ***
## pan           0.4623     0.2879   1.606    0.108    
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## (Dispersion parameter for binomial family taken to be 1)
## 
##     Null deviance: 382.78  on 784  degrees of freedom
## Residual deviance: 380.23  on 783  degrees of freedom
## AIC: 384.23
## 
## Number of Fisher Scoring iterations: 5
glm17 <- glm(day30 ~ fam, data = df, family = binomial)
summary(glm17)
## 
## Call:
## glm(formula = day30 ~ fam, family = binomial, data = df)
## 
## Coefficients:
##             Estimate Std. Error z value Pr(>|z|)    
## (Intercept)  -2.5281     0.1782 -14.186   <2e-16 ***
## fam          -0.3084     0.3009  -1.025    0.305    
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## (Dispersion parameter for binomial family taken to be 1)
## 
##     Null deviance: 382.78  on 784  degrees of freedom
## Residual deviance: 381.70  on 783  degrees of freedom
## AIC: 385.7
## 
## Number of Fisher Scoring iterations: 5
glm18 <- glm(day30 ~ ste, data = df, family = binomial)
summary(glm18)
## 
## Call:
## glm(formula = day30 ~ ste, family = binomial, data = df)
## 
## Coefficients:
##             Estimate Std. Error z value Pr(>|z|)    
## (Intercept) -2.89538    0.37710  -7.678 1.61e-14 ***
## ste          0.05738    0.07872   0.729    0.466    
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## (Dispersion parameter for binomial family taken to be 1)
## 
##     Null deviance: 382.78  on 784  degrees of freedom
## Residual deviance: 382.25  on 783  degrees of freedom
## AIC: 386.25
## 
## Number of Fisher Scoring iterations: 5
glm19 <- glm(day30 ~ st4, data = df, family = binomial)
summary(glm19)
## 
## Call:
## glm(formula = day30 ~ st4, family = binomial, data = df)
## 
## Coefficients:
##             Estimate Std. Error z value Pr(>|z|)    
## (Intercept)  -2.8149     0.2019 -13.942   <2e-16 ***
## st4           0.3726     0.2874   1.297    0.195    
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## (Dispersion parameter for binomial family taken to be 1)
## 
##     Null deviance: 382.78  on 784  degrees of freedom
## Residual deviance: 381.10  on 783  degrees of freedom
## AIC: 385.1
## 
## Number of Fisher Scoring iterations: 5
glm20 <- glm(day30 ~ ttr, data = df, family = binomial)
summary(glm20)
## 
## Call:
## glm(formula = day30 ~ ttr, family = binomial, data = df)
## 
## Coefficients:
##             Estimate Std. Error z value Pr(>|z|)    
## (Intercept)  -3.0285     0.2413 -12.550   <2e-16 ***
## ttr           0.6660     0.3007   2.215   0.0268 *  
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## (Dispersion parameter for binomial family taken to be 1)
## 
##     Null deviance: 382.78  on 784  degrees of freedom
## Residual deviance: 377.64  on 783  degrees of freedom
## AIC: 381.64
## 
## Number of Fisher Scoring iterations: 5

Predictores con asociación estadísticamente significativa (p < 0.05):

Predictor Estimate OR (e^β) p-valor Interpretación
age 0.106 1.11 < 0.001 Cada año adicional de edad aumenta el odds de muerte a 30 días en un 11%.
a65 1.645 5.18 < 0.001 Tener ≥65 años se asocia a 5 veces más odds de muerte a 30 días.
killip 1.163 3.20 < 0.001 Cada unidad adicional en la clase Killip se asocia a 3.2 veces más odds.
sho 2.078 7.99 < 0.001 Shock se asocia con casi 8 veces más odds de muerte.
hrt 1.185 3.27 < 0.001 Presencia de insuficiencia cardíaca aumenta 3.3 veces los odds.
pmi 1.069 2.91 < 0.001 Infarto previo aumenta el odds casi 3 veces.
hei -0.051 0.95 0.001 A mayor estatura, menor probabilidad de morir.
wei -0.042 0.96 < 0.001 A mayor peso, menor odds de muerte.
ant 0.640 1.90 0.026 Infarto anterior se asocia a casi 2 veces más odds.
smk 0.445 1.56 0.018 Fumar se asocia a 56% más odds de morir.

Question 2: Modeling decisions and preliminary model

Decide whether you will use continuous or dichotomized versions of age (AGE/A65), Killip class (Killip/SHO), and ST elevation (STE/ST4).

## Package epiR 2.0.83 is loaded
## Type help(epi.about) for summary information
## Type browseVignettes(package = 'epiR') to learn how to use epiR for applied epidemiological analyses
## 
##              Outcome +    Outcome -      Total                 Inc risk *
## Exposed +          446          287        733     60.85 (57.21 to 64.40)
## Exposed -           12           40         52     23.08 (12.53 to 36.84)
## Total              458          327        785     58.34 (54.81 to 61.82)
## 
## Point estimates and 95% CIs:
## -------------------------------------------------------------------
## Inc risk ratio                                 2.64 (1.60, 4.35)
## Inc odds ratio                                 5.18 (2.67, 10.04)
## Attrib risk in the exposed *                   37.77 (25.78, 49.75)
## Attrib fraction in the exposed (%)            62.07 (37.49, 76.99)
## Attrib risk in the population *                35.27 (23.31, 47.23)
## Attrib fraction in the population (%)         60.45 (35.65, 75.69)
## -------------------------------------------------------------------
## Uncorrected chi2 test that OR = 1: chi2(1) = 28.499 Pr>chi2 = <0.001
## Fisher exact test that OR = 1: Pr>chi2 = <0.001
##  Wald confidence limits
##  CI: confidence interval
##  * Outcomes per 100 population units
##              Outcome +    Outcome -      Total                 Inc risk *
## Exposed +          446          287        733     60.85 (57.21 to 64.40)
## Exposed -           12           40         52     23.08 (12.53 to 36.84)
## Total              458          327        785     58.34 (54.81 to 61.82)
## 
## Point estimates and 95% CIs:
## -------------------------------------------------------------------
## Inc risk ratio                                 2.64 (1.60, 4.35)
## Inc odds ratio                                 5.18 (2.67, 10.04)
## Attrib risk in the exposed *                   37.77 (25.78, 49.75)
## Attrib fraction in the exposed (%)            62.07 (37.49, 76.99)
## Attrib risk in the population *                35.27 (23.31, 47.23)
## Attrib fraction in the population (%)         60.45 (35.65, 75.69)
## -------------------------------------------------------------------
## Uncorrected chi2 test that OR = 1: chi2(1) = 28.499 Pr>chi2 = <0.001
## Fisher exact test that OR = 1: Pr>chi2 = <0.001
##  Wald confidence limits
##  CI: confidence interval
##  * Outcomes per 100 population units

La variable edad se conservó en forma dicotómica (a65) debido a su fuerte asociación estadística con la mortalidad a 30 días (OR ≈ 5.18, p < 0.001) y por su relevancia clínica al establecer un punto de corte significativo (≥65 años) que permite una interpretación sencilla en el contexto asistencial. En cuanto a la clase Killip, se eligió la versión ordinal completa (KILLIP) ya que mostró una relación creciente y significativa con el riesgo de muerte (p < 0.001), en contraste con la variable dicotómica SHO (Killip 4), que representa solo el extremo más grave de la clasificación y no refleja adecuadamente la gradación del riesgo. Finalmente, se decidió mantener la variable STE como continua, ya que su forma dicotómica (ST4, ≥4 derivaciones con elevación del ST) no evidenció una asociación significativa con el desenlace (p = 0.14), y la versión continua puede captar mejor posibles relaciones lineales o no lineales con el desenlace.

Decide on your modeling strategy for the definition of the multivariable regression model, e.g. a full model including all potential predictors, backward stepwise with a user-specified p-value (e.g.0.15), ‘Sign OK’ selection (manually), etc.

Para la construcción del modelo de regresión logística multivariable que explica la mortalidad a 30 días, se empleó una estrategia de selección hacia atrás (backward elimination), partiendo de un modelo completo que incluyó todos los predictores con relevancia clínica o con una asociación univariada con el desenlace (p < 0.20). Se utilizó un umbral de eliminación de p = 0.15, más flexible que el tradicional, con el objetivo de retener variables potencialmente importantes como confusoras, incluso si no alcanzaban significancia estadística individual. Esta estrategia busca lograr un equilibrio entre parsimonia y ajuste adecuado, minimizando el riesgo de sobreajuste. Adicionalmente, se conservaron variables con fuerte plausibilidad clínica, aunque no cumplieran el criterio estadístico, siguiendo un enfoque complementario de “Signo OK”, que integra evidencia médica y razonamiento estadístico en la selección final del modelo.

## Warning: package 'broom' was built under R version 4.4.3
## Eliminando: sex con p = 0.8218751 
## Eliminando: ste con p = 0.4223717 
## Eliminando: st4 con p = 0.7656482 
## Eliminando: dia con p = 0.2563152
## 
## Call:
## glm(formula = nueva_formula, family = binomial, data = df)
## 
## Coefficients:
##             Estimate Std. Error z value Pr(>|z|)    
## (Intercept)  -5.3303     0.4843 -11.006  < 2e-16 ***
## a65           1.3019     0.3562   3.655 0.000257 ***
## pmi           0.6922     0.3277   2.112 0.034675 *  
## killip        0.6867     0.2349   2.923 0.003469 ** 
## hrt           0.9709     0.3148   3.084 0.002043 ** 
## hyp           0.8897     0.5420   1.641 0.100706    
## ttr           0.6223     0.3191   1.950 0.051196 .  
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## (Dispersion parameter for binomial family taken to be 1)
## 
##     Null deviance: 382.78  on 784  degrees of freedom
## Residual deviance: 319.31  on 778  degrees of freedom
## AIC: 333.31
## 
## Number of Fisher Scoring iterations: 6

Show the regression coefficients of your preliminary model + motivation for inclusion of the covariable in the model.

Modelo preliminar de regresión logística multivariable para mortalidad a 30 días

Covariable Coeficiente (β) OR (exp(β)) Valor p Justificación para inclusión
(Intercepto) -5.3303 < 0.001 Representa el logit de la mortalidad cuando todas las covariables valen 0.
a65 (edad ≥ 65 años) 1.3019 3.67 0.0003 Edad avanzada es un predictor clínico bien establecido de peor pronóstico en eventos cardiovasculares. Se retuvo por significancia estadística y relevancia clínica.
pmi (infarto previo) 0.6922 1.99 0.035 Los antecedentes de infarto aumentan el riesgo de mortalidad. Se incluyó por su asociación univariada y plausibilidad fisiopatológica.
killip (clase Killip elevada) 0.6867 1.99 0.0035 La clase Killip es un fuerte predictor de mortalidad en pacientes con síndrome coronario agudo. Alta validez clínica y estadística.
hrt (frecuencia cardíaca elevada) 0.9709 2.64 0.0020 La taquicardia refleja inestabilidad hemodinámica. Variable clínicamente relevante y estadísticamente significativa.
hyp (hipertensión) 0.8897 2.43 0.101 Aunque no fue estadísticamente significativa, se mantuvo por su potencial rol como confusora y alta prevalencia en población cardiovascular.
ttr (tiempo a reperfusión > 120 min) 0.6223 1.86 0.051 El retraso en la reperfusión se asocia con mayor daño miocárdico y peor pronóstico. Se retuvo por estar cerca del umbral y por su importancia clínica.

Question 3: Interaction terms

Decide whether interaction terms will be included; use LR tests.

# Interacción: a65 * hrt
modelo_base <- glm(day30 ~ a65 + pmi + killip + hrt + hyp + ttr, data = df, family = binomial)
modelo_a65_hrt <- glm(day30 ~ a65 * hrt + pmi + killip + hyp + ttr, data = df, family = binomial)
anova(modelo_base, modelo_a65_hrt, test = "LRT")
## Analysis of Deviance Table
## 
## Model 1: day30 ~ a65 + pmi + killip + hrt + hyp + ttr
## Model 2: day30 ~ a65 * hrt + pmi + killip + hyp + ttr
##   Resid. Df Resid. Dev Df Deviance Pr(>Chi)  
## 1       778     319.31                       
## 2       777     315.53  1   3.7755  0.05201 .
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
# Interacción: pmi * ttr
modelo_pmi_ttr <- glm(day30 ~ a65 + pmi * ttr + killip + hrt + hyp, data = df, family = binomial)
anova(modelo_base, modelo_pmi_ttr, test = "LRT")
## Analysis of Deviance Table
## 
## Model 1: day30 ~ a65 + pmi + killip + hrt + hyp + ttr
## Model 2: day30 ~ a65 + pmi * ttr + killip + hrt + hyp
##   Resid. Df Resid. Dev Df  Deviance Pr(>Chi)
## 1       778     319.31                      
## 2       777     319.31  1 0.0020989   0.9635
# Interacción: killip * hrt

modelo_killip_hrt <- glm(day30 ~ a65 + pmi + killip * hrt + hyp + ttr, data = df, family = binomial)
anova(modelo_base, modelo_killip_hrt, test = "LRT")
## Analysis of Deviance Table
## 
## Model 1: day30 ~ a65 + pmi + killip + hrt + hyp + ttr
## Model 2: day30 ~ a65 + pmi + killip * hrt + hyp + ttr
##   Resid. Df Resid. Dev Df Deviance Pr(>Chi)
## 1       778     319.31                     
## 2       777     318.95  1  0.35919    0.549

Se exploraron tres interacciones clínicamente plausibles utilizando pruebas de razón de verosimilitud (Likelihood Ratio Tests), comparando el modelo base con modelos que incluían cada interacción por separado:

  • Para la interacción entre edad ≥ 65 años y taquicardia (a65 * hrt), la desviancia residual del modelo base fue 319.31 (df = 778), mientras que el modelo con la interacción presentó una desviancia de 315.53 (df = 777). La reducción en la desviancia fue de 3.78, con un valor p = 0.052, lo que sugiere una tendencia no significativa.

  • La interacción entre infarto previo y tiempo a reperfusión (pmi * ttr) no mejoró el ajuste del modelo. La desviancia se mantuvo en 319.31 en ambos modelos (df = 778 vs. 777), con una diferencia mínima de 0.002 y un valor p = 0.964, indicando ausencia total de efecto de interacción.

  • La interacción entre clase Killip y frecuencia cardíaca (killip * hrt) resultó en una desviancia de 318.95 frente a 319.31 en el modelo base, con una diferencia de 0.36 y valor p = 0.549, lo que indica que tampoco fue significativa.

Question 4: Model performance

Determine the goodness-of-fit of the model with the Hosmer-Lemeshow test.

library(ResourceSelection)
## Warning: package 'ResourceSelection' was built under R version 4.4.3
## ResourceSelection 0.3-6   2023-06-27
hl_test <- hoslem.test(df$day30, fitted(modelo), g = 10)
## Warning in hoslem.test(df$day30, fitted(modelo), g = 10): The data did not
## allow for the requested number of bins.
print(hl_test)
## 
##  Hosmer and Lemeshow goodness of fit (GOF) test
## 
## data:  df$day30, fitted(modelo)
## X-squared = 2.8761, df = 6, p-value = 0.8242

Se construyó un modelo de regresión logística multivariable mediante selección hacia atrás, eliminando progresivamente las variables con valor p > 0.15. El modelo final mostró un buen ajuste a los datos según la prueba de Hosmer-Lemeshow (Chi² = 2.88, gl = 6, p = 0.824), sin evidencia de mal ajuste.

Determine the discriminative ability by calculating the area under the ROC curve.

library(pROC)
## Type 'citation("pROC")' for a citation.
## 
## Adjuntando el paquete: 'pROC'
## The following object is masked from 'package:gmodels':
## 
##     ci
## The following object is masked from 'package:epiDisplay':
## 
##     ci
## The following objects are masked from 'package:stats':
## 
##     cov, smooth, var
roc_obj <- roc(df$day30, fitted(modelo))
## Setting levels: control = 0, case = 1
## Setting direction: controls < cases
auc(roc_obj)
## Area under the curve: 0.8016
plot(roc_obj,
     main = "Curva ROC - Modelo final",
     col = "blue",
     lwd = 2)

abline(a = 0, b = 1, lty = 2, col = "gray")  # Línea de referencia

La capacidad discriminativa del modelo fue evaluada mediante el área bajo la curva ROC. El AUC fue de 0.80, lo que indica que el modelo tiene una buena capacidad para discriminar entre pacientes que fallecieron y los que sobrevivieron a los 30 días.

Determine the calibration plot

library(rms)
## Warning: package 'rms' was built under R version 4.4.3
## Cargando paquete requerido: Hmisc
## 
## Adjuntando el paquete: 'Hmisc'
## The following objects are masked from 'package:summarytools':
## 
##     label, label<-
## The following objects are masked from 'package:dplyr':
## 
##     src, summarize
## The following objects are masked from 'package:base':
## 
##     format.pval, units
## Registered S3 method overwritten by 'rms':
##   method       from      
##   print.lrtest epiDisplay
## 
## Adjuntando el paquete: 'rms'
## The following object is masked from 'package:epiDisplay':
## 
##     lrtest
dd <- datadist(df)
## Warning in datadist(df): esamp is constant
## Warning in datadist(df): grpl is constant
## Warning in datadist(df): regl is constant
options(datadist = "dd")
modelo_lrm <- lrm(day30 ~ a65 + pmi + killip + hrt + hyp + ttr, data = df, x = TRUE, y = TRUE)
cal <- calibrate(modelo_lrm, method = "boot", B = 200)
plot(cal, 
     xlab = "Probabilidad predicha", 
     ylab = "Probabilidad observada", 
     main = "Gráfica de calibración del modelo")

## 
## n=785   Mean absolute error=0.008   Mean squared error=0.00016
## 0.9 Quantile of absolute error=0.018

La calibración del modelo se evaluó mediante un gráfico de calibración obtenido por validación bootstrap (200 repeticiones). El modelo mostró un error absoluto medio de 0.009 y un error cuadrático medio de 0.00017, lo que indica que las probabilidades predichas se ajustan muy bien a las probabilidades observadas. Además, el percentil 90 del error absoluto fue de 0.019, lo que refleja un excelente desempeño en la mayoría de las predicciones.

Question 5: Presentation

Present the final model as a regression formula

summary(modelo)
## 
## Call:
## glm(formula = nueva_formula, family = binomial, data = df)
## 
## Coefficients:
##             Estimate Std. Error z value Pr(>|z|)    
## (Intercept)  -5.3303     0.4843 -11.006  < 2e-16 ***
## a65           1.3019     0.3562   3.655 0.000257 ***
## pmi           0.6922     0.3277   2.112 0.034675 *  
## killip        0.6867     0.2349   2.923 0.003469 ** 
## hrt           0.9709     0.3148   3.084 0.002043 ** 
## hyp           0.8897     0.5420   1.641 0.100706    
## ttr           0.6223     0.3191   1.950 0.051196 .  
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## (Dispersion parameter for binomial family taken to be 1)
## 
##     Null deviance: 382.78  on 784  degrees of freedom
## Residual deviance: 319.31  on 778  degrees of freedom
## AIC: 333.31
## 
## Number of Fisher Scoring iterations: 6

FORMULA:

logit(P)= −5.3303+1.3019⋅a65+0.6922⋅pmi+0.6867⋅killip+0.9709⋅hrt+0.8897⋅hyp+0.6223⋅ttr

El logit de la probabilidad de muerte a 30 días aumenta en:

1.3019 unidades si el paciente tiene 65 años o más (a65 = 1).

0.6922 unidades si tiene antecedente de infarto previo (pmi = 1).

0.6867 por cada unidad de aumento en la clase Killip.

0.9709 unidades si tiene taquicardia al ingreso (hrt = 1).

0.8897 unidades si presenta hipotensión (hyp = 1).

0.6223 unidades por cada unidad de aumento en el tiempo hasta reperfusión (ttr).

Cuando todas las variables valen 0 (paciente joven, sin infarto previo, Killip 0, sin taquicardia, sin hipotensión y reperfusión inmediata), el logit(P) es igual a –5.3303.

Present the final model as a clinical prediction rule in a format that you think that clinicians will appreciate.

Suggestions: a score chart with scores based on 10 times the rounded regression coefficients, a table, etc.

# Función para calcular score clínico y probabilidad
calcular_riesgo <- function(a65, pmi, killip, hrt, hyp, ttr) {
  # Coeficientes del modelo (estimaciones del glm)
  intercepto <- -5.3303
  coef_a65   <- 1.3019
  coef_pmi   <- 0.6922
  coef_killip <- 0.6867
  coef_hrt   <- 0.9709
  coef_hyp   <- 0.8897
  coef_ttr   <- 0.6223

  # Cálculo del logit
  logit <- intercepto +
           coef_a65 * a65 +
           coef_pmi * pmi +
           coef_killip * killip +
           coef_hrt * hrt +
           coef_hyp * hyp +
           coef_ttr * ttr

  # Transformar logit a probabilidad
  prob <- 1 / (1 + exp(-logit))

  # Calcular score clínico basado en coef × 10 redondeado
  score <- a65 * round(10 * coef_a65) +
           pmi * round(10 * coef_pmi) +
           killip * round(10 * coef_killip) +
           hrt * round(10 * coef_hrt) +
           hyp * round(10 * coef_hyp) +
           ttr * round(10 * coef_ttr)

  # Mostrar resultados
  cat("Puntaje clínico total:", score, "puntos\n")
  cat("Probabilidad estimada de mortalidad a 30 días:", round(prob * 100, 2), "%\n")
}
library(shiny)
## 
## Adjuntando el paquete: 'shiny'
## The following object is masked from 'package:rms':
## 
##     validate
# Define la interfaz
ui <- fluidPage(
  titlePanel("Calculadora de Riesgo de Mortalidad a 30 días"),

  sidebarLayout(
    sidebarPanel(
      checkboxInput("a65", "Edad ≥ 65 años", value = FALSE),
      checkboxInput("pmi", "Infarto previo (PMI)", value = FALSE),
      selectInput("killip", "Clase Killip", choices = c(1, 2, 3, 4), selected = 1),
      checkboxInput("hrt", "Frecuencia cardíaca ≥ 80 bpm", value = FALSE),
      checkboxInput("hyp", "Hipotensión (PAS < 100 mmHg)", value = FALSE),
      numericInput("ttr", "Tiempo hasta mejora del dolor de pecho (horas)", value = 0, min = 0, step = 0.1),
      actionButton("calcular", "Calcular Riesgo")
    ),

    mainPanel(
      verbatimTextOutput("resultado")
    )
  )
)

# Define la lógica
server <- function(input, output) {
  observeEvent(input$calcular, {
    # Coeficientes del modelo
    intercepto <- -5.3303
    coef_a65   <- 1.3019
    coef_pmi   <- 0.6922
    coef_killip <- 0.6867
    coef_hrt   <- 0.9709
    coef_hyp   <- 0.8897
    coef_ttr   <- 0.6223

    # Variables binarias convertidas a 0/1
    a65 <- as.numeric(input$a65)
    pmi <- as.numeric(input$pmi)
    hrt <- as.numeric(input$hrt)
    hyp <- as.numeric(input$hyp)
    killip <- as.numeric(input$killip)
    ttr <- input$ttr

    # Cálculo del logit y probabilidad
    logit <- intercepto + coef_a65*a65 + coef_pmi*pmi + coef_killip*killip +
             coef_hrt*hrt + coef_hyp*hyp + coef_ttr*ttr
    prob <- 1 / (1 + exp(-logit))

    # Score clínico basado en coef × 10
    score <- a65*round(10*coef_a65) +
             pmi*round(10*coef_pmi) +
             killip*round(10*coef_killip) +
             hrt*round(10*coef_hrt) +
             hyp*round(10*coef_hyp) +
             round(10*coef_ttr*ttr)

    output$resultado <- renderText({
      paste0("Puntaje clínico total: ", score, " puntos\n",
             "Probabilidad estimada de mortalidad a 30 días: ", round(prob*100, 2), "%")
    })
  })
}

# Ejecuta la aplicación
shinyApp(ui = ui, server = server)
Shiny applications not supported in static R Markdown documents