1 Datos

Contexto

Las enfermedades cardiovasculares (ECV) son la principal causa de muerte a nivel mundial y se cobran aproximadamente 17,9 millones de vidas cada año, lo que representa el 31% de todas las muertes en todo el mundo. Cuatro de cada cinco muertes por ECV se deben a ataques cardíacos y accidentes cerebrovasculares, y un tercio de estas muertes ocurren prematuramente en personas menores de 70 años. La insuficiencia cardíaca es un evento común causado por ECV y este conjunto de datos contiene 11 características que pueden usarse para predecir una posible enfermedad cardíaca.

Las personas con enfermedades cardiovasculares o que tienen un alto riesgo cardiovascular (debido a la presencia de uno o más factores de riesgo como hipertensión, diabetes, hiperlipidemia o enfermedad ya establecida) necesitan una detección y un tratamiento tempranos en los que un modelo de aprendizaje automático puede ser de gran ayuda.

Información del atributo

  • Edad: edad del paciente [años]

  • Sexo: sexo del paciente [M: Masculino, F: Femenino]

  • Tipo de dolor en el pecho: tipo de dolor en el pecho [TA: angina típica, ATA: angina atípica, NAP: dolor no angular, ASY: asintomático]

  • Presión arterial en reposo: presión arterial en reposo [mm Hg]

  • Colesterol: colesterol sérico [mm/dl]

  • FastingBS: azúcar en sangre en ayunas [1: si FastingBS > 120 mg/dl, 0: en caso contrario]

  • ECG en reposo: resultados del electrocardiograma en reposo [Normal: Normal, ST: con anomalía de la onda ST-T (inversiones de la onda T y/o elevación o depresión del ST de > 0,05 mV), HVI: que muestra hipertrofia ventricular izquierda probable o definitiva según los criterios de Estes]

  • MaxHR: frecuencia cardíaca máxima alcanzada [Valor numérico entre 60 y 202]

  • EjercicioAngina: angina inducida por el ejercicio [Y: Sí, N: No]

  • Oldpeak: oldpeak = ST [Valor numérico medido en depresión]

  • ST_Slope: la pendiente del segmento ST de ejercicio máximo [Arriba: pendiente ascendente, Plano: plano, Abajo: pendiente descendente]

  • Enfermedad cardíaca: clase de salida [1: enfermedad cardíaca, 0: normal]

1.1 Pre - procesamiento de datos

Lectura de datos

datos <- read_csv("heart.csv")
head(datos,6)
## # A tibble: 6 × 12
##     Age Sex   ChestPainType RestingBP Cholesterol FastingBS RestingECG MaxHR
##   <dbl> <chr> <chr>             <dbl>       <dbl>     <dbl> <chr>      <dbl>
## 1    40 M     ATA                 140         289         0 Normal       172
## 2    49 F     NAP                 160         180         0 Normal       156
## 3    37 M     ATA                 130         283         0 ST            98
## 4    48 F     ASY                 138         214         0 Normal       108
## 5    54 M     NAP                 150         195         0 Normal       122
## 6    39 M     NAP                 120         339         0 Normal       170
## # ℹ 4 more variables: ExerciseAngina <chr>, Oldpeak <dbl>, ST_Slope <chr>,
## #   HeartDisease <dbl>

Cambio de nombres

datos = datos %>% 
  rename(
    edad = Age,
    sexo = Sex,
    tipo_dolor_pecho = ChestPainType,
    presion_arterial = RestingBP,
    colesterol = Cholesterol,
    glucemia_ayunas = FastingBS,
    ecg_reposo = RestingECG,        
    frecuencia_maxima = MaxHR,
    angina_ejercicio = ExerciseAngina,
    depresion_st = Oldpeak,
    pendiente_st = ST_Slope,
    enfermedad_cardiaca = HeartDisease
  )

Cambiamos los niveles

datos %>% mutate(sexo = case_match(sexo, "M" ~ "Masculino", "F"~"Femenino"),
                 tipo_dolor_pecho = case_match(tipo_dolor_pecho,
                                               "TA" ~ "Angina Típica",
                                               "ATA" ~ "Angina Atípica",
                                               "NAP" ~ "Dolor No Anginoso",
                                               "ASY" ~ "Asintomático"),
                 angina_ejercicio = case_match(angina_ejercicio,
                                               "Y" ~ "Sí",
                                               "N" ~ "No")) -> datos

Colocamos a factor las variables correspondientes

datos <- datos %>% mutate(across(c(enfermedad_cardiaca, sexo, tipo_dolor_pecho, ecg_reposo,
                                   angina_ejercicio, pendiente_st, glucemia_ayunas), as.factor))
# para ver los tipos de datos en general
glimpse(datos)
## Rows: 918
## Columns: 12
## $ edad                <dbl> 40, 49, 37, 48, 54, 39, 45, 54, 37, 48, 37, 58, 39…
## $ sexo                <fct> Masculino, Femenino, Masculino, Femenino, Masculin…
## $ tipo_dolor_pecho    <fct> Angina Atípica, Dolor No Anginoso, Angina Atípica,…
## $ presion_arterial    <dbl> 140, 160, 130, 138, 150, 120, 130, 110, 140, 120, …
## $ colesterol          <dbl> 289, 180, 283, 214, 195, 339, 237, 208, 207, 284, …
## $ glucemia_ayunas     <fct> 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,…
## $ ecg_reposo          <fct> Normal, Normal, ST, Normal, Normal, Normal, Normal…
## $ frecuencia_maxima   <dbl> 172, 156, 98, 108, 122, 170, 170, 142, 130, 120, 1…
## $ angina_ejercicio    <fct> No, No, No, Sí, No, No, No, No, Sí, No, No, Sí, No…
## $ depresion_st        <dbl> 0.0, 1.0, 0.0, 1.5, 0.0, 0.0, 0.0, 0.0, 1.5, 0.0, …
## $ pendiente_st        <fct> Up, Flat, Up, Flat, Up, Up, Up, Up, Flat, Up, Up, …
## $ enfermedad_cardiaca <fct> 0, 1, 0, 1, 0, 0, 0, 0, 1, 0, 0, 1, 0, 1, 0, 0, 1,…

Datos de referencia

Vemos de forma visual los niveles de referencia según cada factor, para luego analizar si debemos mantener esa misma referencia o poder cambiarla

contrasts(datos$sexo)
##           Masculino
## Femenino          0
## Masculino         1
contrasts(datos$tipo_dolor_pecho)
##                   Angina Típica Asintomático Dolor No Anginoso
## Angina Atípica                0            0                 0
## Angina Típica                 1            0                 0
## Asintomático                  0            1                 0
## Dolor No Anginoso             0            0                 1
contrasts(datos$glucemia_ayunas)
##   1
## 0 0
## 1 1
contrasts(datos$pendiente_st)
##      Flat Up
## Down    0  0
## Flat    1  0
## Up      0  1
contrasts(datos$enfermedad_cardiaca)
##   1
## 0 0
## 1 1

Cambiamos la referencia para un mejor análisis de los RR

datos$tipo_dolor_pecho = relevel(datos$tipo_dolor_pecho, ref = "Asintomático")
datos$pendiente_st = relevel(datos$pendiente_st, ref = "Up")
contrasts(datos$tipo_dolor_pecho)
##                   Angina Atípica Angina Típica Dolor No Anginoso
## Asintomático                   0             0                 0
## Angina Atípica                 1             0                 0
## Angina Típica                  0             1                 0
## Dolor No Anginoso              0             0                 1
contrasts(datos$pendiente_st)
##      Down Flat
## Up      0    0
## Down    1    0
## Flat    0    1
contrasts(datos$enfermedad_cardiaca)
##   1
## 0 0
## 1 1

0 no tiene enfermedad, 1 tiene enfermedad

2 ¿Por qué usar RR en vez de OR?

Como es de conocimiento la regresión logística dicotómica como tal modela ODDS, que luego se linealiza aplicando el logaritmo neperiano a cada miembro de nuestra ecuación de regresión, sin embargo, éste modelo no es adecuado usarlo para modelar RR, que es nuestro objetivo en este estudio; es importante mencionar que usar RR es mejor que OR en algunos casos, por ejemplo: usando la covariable tipo de dolor de pecho

table(datos$tipo_dolor_pecho,datos$enfermedad_cardiaca)-> tabla; tabla
##                    
##                       0   1
##   Asintomático      104 392
##   Angina Atípica    149  24
##   Angina Típica      26  20
##   Dolor No Anginoso 131  72
addmargins(tabla,margin = 2)
##                    
##                       0   1 Sum
##   Asintomático      104 392 496
##   Angina Atípica    149  24 173
##   Angina Típica      26  20  46
##   Dolor No Anginoso 131  72 203

Si hallamos los RR y OR para cada grupo de tipos de dolor de pecho

Razón de riesgo

# RR de asintomatico 
riesgo_asin = 392/(104+392); riesgo_asin
## [1] 0.7903226
# RR de Angina atipica 
riesgo_at = 24/(149+24);riesgo_at
## [1] 0.1387283
RR = riesgo_asin/riesgo_at;RR
## [1] 5.696909

Los asintomáticos tienen 5.69 (mayor en 469%) veces el riesgo de estar enfermos que de los de pacientes con dolor de pecho angina atípica.

Hemos visto una interpretación de muchas sobre el RR, ahora veamos OR

ODDS Ratio

odds_asin = 392/104; odds_asin
## [1] 3.769231
odds_at = 24/149;odds_at
## [1] 0.1610738
OR1 = odds_asin/odds_at; OR1
## [1] 23.40064

Los asintomáticos tienen 23 veces más chances de estar enfermos que los paciente con dolor de pecho de angina atípica.

Vemos que hay una gran diferencia entre los resultados, he ahí donde el OR podría estar dando conclusiones erróneas, por ese motivo el RR puede ser más confiable.

Hemos demostrado de manera simple del por qué algunas veces es mejor usar modelos que modelen RR en vez de OR; por ese motivo la Regresión Poisson robusta toma preeminencia

3 Modelo de Regresión Poisson Robusta

Sea el modelo

\[log(\mu_i) = \beta_1 + \beta_2X_{2i} + \beta_3X_{3i} + ... + \beta_kX_{ki} \] Donde \(\mu\) es el riesgo esperado para el individuo i

Antes de seguir con el estudio, si sabemos que la variable respuesta es una binomial, ¿Por qué modelamos con la poisson?

Tener en cuenta que sea X~Poisson(\(\lambda\)) asume que media = varianza = \(\lambda\).

Según la binomial (el origen real de la Variable aleatoria) asume que la media \(\neq\) varianza.

¿cómo sabiendo esa diferencia importante, podemos usar la regresión Poisson?

Para demostrar lo que acabo de mencionar, usaré la siguiente tabla:

Según modelo binomial

Sea: \(P1 = a/n1\)

Var(P1) = Var(a/n1) = \(\frac{n_{1}p_{1}(1-p_{1})}{n_1^2} = \frac{p_{1}(1-p_{1})}{n_{1}}\)

Modelo log binomial

Var(log(p1)) = \(\frac{Var(p)}{p_1^2}\) Se cumple eso según la varianza transformada por el método delta

Var(log(p1)) = \(\frac{\frac{p_{1}(1-p_{1})}{n_1}}{p_1^2} = \frac{1-p_{1}}{n_1p_1}\)

Sabemos que p1 = a/n1 –> n1p1 = a; por lo tanto

var(log(p1)) = \(\frac{1-p_{1}}{a} = \frac{1}{a} - \frac{p}{a} = \frac{1}{a} - \frac{a/n_1}{a} = \frac{1}{a} - \frac{1}{n_1}\)

Según modelo Poisson

Var(p1) = Var(a/n1) = \(\frac{n_{1}p_{1}}{n_1^2} = \frac{p_{1}}{n_{1}}\)

Var(log(p1)) = \(\frac{Var(p)}{p_1^2} = \frac{p_1/n_1}{p_1^2} = \frac{1}{n_1p_1} = \frac{1}{a}\)

Vemos que según la varianza verdadera de la binomial, según la poisson difiere

\(Var(log(p_1)) = \frac{1}{a} - \frac{1}{n_1}\) varianza según binomial

\(Var(log(p_1)) = \frac{1}{a}\) Varianza según poisson

Se puede ver que difieren en la expresión 1/n1, por ese motivo, la librería sandwich corrige esa estimación con un factor de conversión, conviertiendo así, la varianza a varianza robusta he ahí el nombre de Regresión Poisson con Varianza Robusta; luego de haber explicado ello sigamos con el caso de estudio.

datos$enfermedad_cardiaca <- as.numeric(as.character(datos$enfermedad_cardiaca))
modelo <- glm(enfermedad_cardiaca ~ ., family = poisson(link = "log"), data = datos)
summary(modelo)
## 
## Call:
## glm(formula = enfermedad_cardiaca ~ ., family = poisson(link = "log"), 
##     data = datos)
## 
## Coefficients:
##                                     Estimate Std. Error z value Pr(>|z|)    
## (Intercept)                       -1.771e+00  6.240e-01  -2.838 0.004546 ** 
## edad                               6.614e-03  5.769e-03   1.147 0.251583    
## sexoMasculino                      4.660e-01  1.545e-01   3.016 0.002561 ** 
## tipo_dolor_pechoAngina Atípica    -8.970e-01  2.242e-01  -4.000 6.33e-05 ***
## tipo_dolor_pechoAngina Típica     -3.212e-01  2.393e-01  -1.342 0.179497    
## tipo_dolor_pechoDolor No Anginoso -4.584e-01  1.334e-01  -3.436 0.000591 ***
## presion_arterial                   4.652e-05  2.495e-03   0.019 0.985122    
## colesterol                        -8.605e-04  4.068e-04  -2.115 0.034398 *  
## glucemia_ayunas1                   2.057e-01  1.007e-01   2.042 0.041116 *  
## ecg_reposoNormal                  -6.795e-02  1.193e-01  -0.569 0.569083    
## ecg_reposoST                      -7.494e-02  1.390e-01  -0.539 0.589676    
## frecuencia_maxima                 -6.775e-04  2.234e-03  -0.303 0.761662    
## angina_ejercicioSí                 2.151e-01  1.068e-01   2.014 0.044003 *  
## depresion_st                       8.265e-02  4.592e-02   1.800 0.071880 .  
## pendiente_stDown                   6.607e-01  2.062e-01   3.204 0.001355 ** 
## pendiente_stFlat                   9.210e-01  1.394e-01   6.608 3.88e-11 ***
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## (Dispersion parameter for poisson family taken to be 1)
## 
##     Null deviance: 601.18  on 917  degrees of freedom
## Residual deviance: 330.49  on 902  degrees of freedom
## AIC: 1378.5
## 
## Number of Fisher Scoring iterations: 5

4 Selección de variables

Para seleccionar las variables más importantes, debemos de usar la varianza-covarianza robustas para ellono podemos usar el summary normal, usaremos coeftest con las matrices de covarianza robustas usando vcov = sandwich.

coeftest(modelo, vcov = sandwich)
## 
## z test of coefficients:
## 
##                                      Estimate  Std. Error z value  Pr(>|z|)    
## (Intercept)                       -1.7706e+00  3.3165e-01 -5.3386 9.365e-08 ***
## edad                               6.6140e-03  2.8756e-03  2.3000 0.0214457 *  
## sexoMasculino                      4.6600e-01  9.7766e-02  4.7665 1.875e-06 ***
## tipo_dolor_pechoAngina Atípica    -8.9696e-01  1.7474e-01 -5.1331 2.850e-07 ***
## tipo_dolor_pechoAngina Típica     -3.2116e-01  1.5564e-01 -2.0634 0.0390711 *  
## tipo_dolor_pechoDolor No Anginoso -4.5844e-01  7.7981e-02 -5.8789 4.130e-09 ***
## presion_arterial                   4.6518e-05  1.2580e-03  0.0370 0.9705038    
## colesterol                        -8.6049e-04  1.9225e-04 -4.4758 7.612e-06 ***
## glucemia_ayunas1                   2.0569e-01  4.5827e-02  4.4885 7.171e-06 ***
## ecg_reposoNormal                  -6.7947e-02  6.1555e-02 -1.1038 0.2696668    
## ecg_reposoST                      -7.4945e-02  6.6297e-02 -1.1304 0.2582937    
## frecuencia_maxima                 -6.7753e-04  1.1329e-03 -0.5980 0.5498146    
## angina_ejercicioSí                 2.1515e-01  5.2649e-02  4.0865 4.380e-05 ***
## depresion_st                       8.2648e-02  2.2479e-02  3.6768 0.0002362 ***
## pendiente_stDown                   6.6065e-01  1.2365e-01  5.3429 9.146e-08 ***
## pendiente_stFlat                   9.2100e-01  1.0154e-01  9.0704 < 2.2e-16 ***
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1

Solo cogemos las variables que son significativas a un nivel de significancia o P(Error Tipo I) = 0.05

modelo1 <- glm(enfermedad_cardiaca ~ . - presion_arterial - ecg_reposo - frecuencia_maxima,
               family = poisson(link="log"), data = datos)

5 Supuestos

Para corroborar los supuestos usaré el siguiente gráfico

library(performance)
check_model(modelo1)

## Errores estándar robustos

Dado que estamos trabajando con regresion poisson robusta, debemos de hallar los errores estandar robustos que lo usamos con la librería sandwich.

se_robus = sqrt(diag(sandwich(modelo1))); se_robus
##                       (Intercept)                              edad 
##                      0.1903954646                      0.0026822381 
##                     sexoMasculino    tipo_dolor_pechoAngina Atípica 
##                      0.0963917759                      0.1747187064 
##     tipo_dolor_pechoAngina Típica tipo_dolor_pechoDolor No Anginoso 
##                      0.1509500569                      0.0767752475 
##                        colesterol                  glucemia_ayunas1 
##                      0.0001895123                      0.0446278318 
##                angina_ejercicioSí                      depresion_st 
##                      0.0527737444                      0.0220269008 
##                  pendiente_stDown                  pendiente_stFlat 
##                      0.1229673607                      0.1014227672

6 RR e IC

coef(modelo1)->est
# Limite_Inferior = est - 1.96 * se_robus
# Limite_Superior = est + 1.96 * se_robus
IC_log_infe <- est -(1.96*se_robus)
IC_log_supe <- est +(1.96*se_robus)
RR = exp(est); RR
##                       (Intercept)                              edad 
##                         0.1407565                         1.0074476 
##                     sexoMasculino    tipo_dolor_pechoAngina Atípica 
##                         1.5954959                         0.4034508 
##     tipo_dolor_pechoAngina Típica tipo_dolor_pechoDolor No Anginoso 
##                         0.7254945                         0.6302374 
##                        colesterol                  glucemia_ayunas1 
##                         0.9991613                         1.2238350 
##                angina_ejercicioSí                      depresion_st 
##                         1.2416500                         1.0850763 
##                  pendiente_stDown                  pendiente_stFlat 
##                         1.9525921                         2.5321154
tabla_res = data.frame(variable = names(RR),
                       RR = round(RR,3),
                       IC_inf = round(exp(IC_log_infe),3),
                       IC_sup = round(exp(IC_log_supe),3))

tabla_res[,-1]
##                                      RR IC_inf IC_sup
## (Intercept)                       0.141  0.097  0.204
## edad                              1.007  1.002  1.013
## sexoMasculino                     1.595  1.321  1.927
## tipo_dolor_pechoAngina Atípica    0.403  0.286  0.568
## tipo_dolor_pechoAngina Típica     0.725  0.540  0.975
## tipo_dolor_pechoDolor No Anginoso 0.630  0.542  0.733
## colesterol                        0.999  0.999  1.000
## glucemia_ayunas1                  1.224  1.121  1.336
## angina_ejercicioSí                1.242  1.120  1.377
## depresion_st                      1.085  1.039  1.133
## pendiente_stDown                  1.953  1.534  2.485
## pendiente_stFlat                  2.532  2.076  3.089

El modelo quedaría así:

\[ \begin{aligned} \widehat{\text{Riesgo}} &= 0.141 \times 1.007^{(\text{Edad})} \times 1.595^{(\text{SexoMasc})} \\ &\quad \times 0.403^{(\text{AnginaAtípica})} \times 0.725^{(\text{AnginaTípica})} \times 0.630^{(\text{NoAnginoso})} \\ &\quad \times 0.999^{(\text{Colesterol})} \times 1.224^{(\text{GlucemiaAyunas})} \times 1.242^{(\text{AnginaEjerc})} \\ &\quad \times 1.085^{(\text{DepresiónST})} \times 1.953^{(\text{PendienteDown})} \times 2.532^{(\text{PendienteFlat})} \end{aligned} \]

7 Interpretaciones

  • Si la pendiente es Plana (Flat), el riesgo de enfermedad cardiaca se multiplica por 2.5 (aumenta un 153%) comparado con una pendiente ascendente.

  • Si la pendiente es Descendente (Down), el riesgo es casi el doble (1.95 veces) comparado con la ascendente.

  • Ser hombre aumenta el riesgo en un 60% (1.59 veces) comparado con ser mujer.

  • Si el paciente tiene angina inducida por ejercicio, su riesgo aumenta un 1.24 = 24%.

  • Si el paciente tiene glucemia alta en ayunas (1 es >120 mg/dl), su riesgo aumenta un 22%.

  • Tener Angina Atípica reduce el riesgo a un 40% (0.403 < 1) del riesgo que tienen los Asintomáticos.

  • El riesgo aumenta un 0.7% por cada año de vida.

Podemos usar la librería emmeans para hacer interpretaciones con RR ajustados

Se tomará como ejemplo a la covariable dolor de pecho

library(emmeans)
emmeans(modelo1, pairwise ~ tipo_dolor_pecho,
        type = 'response', infer = T)
## $emmeans
##  tipo_dolor_pecho   rate     SE  df asymp.LCL asymp.UCL null z.ratio p.value
##  Asintomático      0.505 0.0497 Inf     0.417     0.613    1  -6.946  <.0001
##  Angina Atípica    0.204 0.0445 Inf     0.133     0.313    1  -7.278  <.0001
##  Angina Típica     0.367 0.0886 Inf     0.228     0.589    1  -4.154  <.0001
##  Dolor No Anginoso 0.319 0.0451 Inf     0.241     0.420    1  -8.073  <.0001
## 
## Results are averaged over the levels of: sexo, glucemia_ayunas, ecg_reposo, angina_ejercicio, pendiente_st 
## Confidence level used: 0.95 
## Intervals are back-transformed from the log scale 
## Tests are performed on the log scale 
## 
## $contrasts
##  contrast                           ratio    SE  df asymp.LCL asymp.UCL null
##  Asintomático / Angina Atípica      2.479 0.553 Inf     1.397      4.40    1
##  Asintomático / Angina Típica       1.378 0.324 Inf     0.753      2.52    1
##  Asintomático / Dolor No Anginoso   1.587 0.209 Inf     1.130      2.23    1
##  Angina Atípica / Angina Típica     0.556 0.172 Inf     0.252      1.23    1
##  Angina Atípica / Dolor No Anginoso 0.640 0.154 Inf     0.345      1.19    1
##  Angina Típica / Dolor No Anginoso  1.151 0.294 Inf     0.598      2.22    1
##  z.ratio p.value
##    4.067  0.0003
##    1.363  0.5226
##    3.498  0.0026
##   -1.901  0.2276
##   -1.850  0.2499
##    0.552  0.9461
## 
## Results are averaged over the levels of: sexo, glucemia_ayunas, ecg_reposo, angina_ejercicio, pendiente_st 
## Confidence level used: 0.95 
## Conf-level adjustment: tukey method for comparing a family of 4 estimates 
## Intervals are back-transformed from the log scale 
## P value adjustment: tukey method for comparing a family of 4 estimates 
## Tests are performed on the log scale

Tomemos el rate = 0.505 de Asintomático; de ¿Dónde sale ese valor?

summary(datos)
##       edad              sexo              tipo_dolor_pecho presion_arterial
##  Min.   :28.00   Femenino :193   Asintomático     :496     Min.   :  0.0   
##  1st Qu.:47.00   Masculino:725   Angina Atípica   :173     1st Qu.:120.0   
##  Median :54.00                   Angina Típica    : 46     Median :130.0   
##  Mean   :53.51                   Dolor No Anginoso:203     Mean   :132.4   
##  3rd Qu.:60.00                                             3rd Qu.:140.0   
##  Max.   :77.00                                             Max.   :200.0   
##    colesterol    glucemia_ayunas  ecg_reposo  frecuencia_maxima
##  Min.   :  0.0   0:704           LVH   :188   Min.   : 60.0    
##  1st Qu.:173.2   1:214           Normal:552   1st Qu.:120.0    
##  Median :223.0                   ST    :178   Median :138.0    
##  Mean   :198.8                                Mean   :136.8    
##  3rd Qu.:267.0                                3rd Qu.:156.0    
##  Max.   :603.0                                Max.   :202.0    
##  angina_ejercicio  depresion_st     pendiente_st enfermedad_cardiaca
##  No:547           Min.   :-2.6000   Up  :395     Min.   :0.0000     
##  Sí:371           1st Qu.: 0.0000   Down: 63     1st Qu.:0.0000     
##                   Median : 0.6000   Flat:460     Median :1.0000     
##                   Mean   : 0.8874                Mean   :0.5534     
##                   3rd Qu.: 1.5000                3rd Qu.:1.0000     
##                   Max.   : 6.2000                Max.   :1.0000

\[ \begin{aligned} \ln(\text{Rate}) &= -1.96 + (0.007 \times 53.51) \\ &\quad + (0.467 \times 0.789) + (-0.001 \times 198.8) \\ &\quad + (0.202 \times 0.233) + (0.217 \times 0.404) \\ &\quad + (0.082 \times 0.887) + (0.669 \times 0.069) \\ &\quad + (0.929 \times 0.501) + (0 + 0 + 0) \end{aligned} \] rate = 0.50

Esos valores nuevos como 53.51, 0.789 son la media o proporción de las variables del caso de estudio, por ello se le dice Razón de Riesgo ajustado.

Se interpreta de la siguiente manera.

El riesgo estimado de presentar enfermedad cardíaca en un paciente con tipo de dolor de pecho Asintomático es del 50.5%, manteniendo todo las demás variables constante.

Ratio

Es la razon de rate(riesgos predichos), la interpretacion se hace en base a la referencia.

¿Como interpretamos el ratio?

  • Si Ratio > 1: El Grupo A tiene más riesgo que el B.
  • Si Ratio < 1: El Grupo A tiene menos riesgo que el B.
  • Si el Intervalo (LCL - UCL) cruza el 1: La diferencia no es significativa (no hay evidencia real de diferencia)

ratio = 2.479

El riesgo ajustado de enfermedad cardíaca en pacientes con dolor Asintomático es 2.48 veces el riesgo de los pacientes con Angina Atípica

ratio = 1.38

El riesgo ajustado de enfermedad cardiaca en pacientes con dolor asintomático es 1.38 veces el riesgo de estar enfermos que los pacientes con dolor de angina tipica

ratio = 0.556

El riesgo ajustado de enfermedad cardiaca en pacientes con dolor angina tipica es 0.556 veces el riesgo de estar enfermos que los pacientes con dolor de angina atipica

Resumen

Table 1. Nice looking table!
Predictor IRR1 95% CI p-value
edad 1.01 1.00, 1.02 0.2
sexo


    Femenino / Masculino 0.63** 0.46, 0.85 0.002
tipo_dolor_pecho


    Asintomático / Angina Atípica 2.48*** 1.40, 4.40 <0.001
    Asintomático / Angina Típica 1.38 0.75, 2.52 0.5
    Asintomático / Dolor No Anginoso 1.59** 1.13, 2.23 0.003
    Angina Atípica / Angina Típica 0.56 0.25, 1.23 0.2
    Angina Atípica / Dolor No Anginoso 0.64 0.34, 1.19 0.2
    Angina Típica / Dolor No Anginoso 1.15 0.60, 2.22 >0.9
colesterol 1.00* 1.00, 1.00 0.033
glucemia_ayunas


    glucemia_ayunas0 / glucemia_ayunas1 0.82* 0.67, 0.99 0.043
angina_ejercicio


    No / Sí 0.81* 0.66, 0.99 0.039
depresion_st 1.09 0.99, 1.19 0.072
pendiente_st


    Up / Down 0.51** 0.32, 0.83 0.003
    Up / Flat 0.39*** 0.29, 0.54 <0.001
    Down / Flat 0.77 0.53, 1.12 0.2
1 *p<0.05; **p<0.01; ***p<0.001
Abbreviations: CI = Confidence Interval, IRR = Incidence Rate Ratio

8 Predicciones

Dado que tenemos el modelo listo, podemos proceder a hacer predicciones

nuevos_pacientes <- data.frame(
  edad = c(65, 45, 55),
  sexo = c("Masculino", "Femenino", "Masculino"), 
  tipo_dolor_pecho = c("Asintomático", "Angina Atípica", "Dolor No Anginoso"),
  colesterol = c(250, 180, 200),
  glucemia_ayunas = c("1", "0", "0"),
  angina_ejercicio = c("Sí", "No", "No"),
  depresion_st = c(2.0, 0.0, 0.5),
  pendiente_st = c("Flat", "Up", "Up"),
  presion_arterial = 120,      
  frecuencia_maxima = 130,    
  ecg_reposo = "Normal"       
)
predicciones <- predict(modelo1, newdata = nuevos_pacientes, type = "response")
resultados <- data.frame(
  Paciente = c("Caso Grave", "Caso Leve", "Caso Medio"),
  Riesgo_Estimado = round(predicciones * 100, 1)
) ; resultados
##     Paciente Riesgo_Estimado
## 1 Caso Grave           133.6
## 2  Caso Leve             6.8
## 3 Caso Medio            18.7

El primer paciente tiene un Caso grave, con un riesgo estimado de 33.6% mayor de contener enfermedad

El segundo paciente tiene un caso leve, con un 6.8% de contener la enfermedad

El tecer paciente tiene un caso medio, con un 18.7% de contener la enfermedadd

9 Curva ROC

#predicciones usando la misma data

predicciones_total = predict(modelo1, type = "response")
curva_roc <- roc(response = datos$enfermedad_cardiaca, predictor = predicciones_total)


# Curva ROC
plot(curva_roc, 
     main = "Curva ROC del Modelo (Validez Interna)",
     col = "blue", 
     print.auc = TRUE) 

auc(curva_roc)
## Area under the curve: 0.9271

Vemos un AUC alto lo que significa que el modelo predice bien a los nuevos individuos, por ejemplo:

Si tomamos al azar a un paciente enfermo y a uno sano de un hospital, el modelo tiene un 92% de probabilidad de asignarle un riesgo más alto al enfermo que al sano.