Introducción

En este taller aprenderemos a calcular e interpretar las tres medidas fundamentales de la epidemiología utilizando R:

  1. Prevalencia (La fotografía estática).
  2. Incidencia Acumulada (Riesgo) y Odds - Cohorte Cerrada (Probabilidad en cohorte cerrada).
  3. Tasa de Incidencia / Densidad (Velocidad en cohorte dinámica).

1. Preparación del Entorno

Antes de empezar, cargamos las “herramientas” necesarias. Asegúrese de tener conexión a internet si es la primera vez que ejecuta estos comandos para descargar las librerías tidyverse, lubridate y epiR.

# --- PASO 0: INSTALACIÓN Y CARGA DE PAQUETES ---

# 1. Si no tiene los paquetes, R los instalará automáticamente con este código:
if(!require(tidyverse)) install.packages("tidyverse")
## Cargando paquete requerido: tidyverse
## ── Attaching core tidyverse packages ──────────────────────── tidyverse 2.0.0 ──
## ✔ dplyr     1.1.4     ✔ readr     2.1.5
## ✔ forcats   1.0.0     ✔ stringr   1.5.2
## ✔ ggplot2   4.0.0     ✔ tibble    3.3.0
## ✔ lubridate 1.9.4     ✔ tidyr     1.3.1
## ✔ purrr     1.1.0     
## ── Conflicts ────────────────────────────────────────── tidyverse_conflicts() ──
## ✖ dplyr::filter() masks stats::filter()
## ✖ dplyr::lag()    masks stats::lag()
## ℹ Use the conflicted package (<http://conflicted.r-lib.org/>) to force all conflicts to become errors
if(!require(lubridate)) install.packages("lubridate")
if(!require(epiR)) install.packages("epiR")
## Cargando paquete requerido: epiR
## Warning: package 'epiR' was built under R version 4.5.2
## Cargando paquete requerido: survival
## Package epiR 2.0.89 is loaded
## Type help(epi.about) for summary information
## Type browseVignettes(package = 'epiR') to learn how to use epiR for applied epidemiological analyses
# 2. Cargar las librerías en la memoria
library(tidyverse)  # Para manipulación de datos
library(lubridate)  # Para manejar fechas
library(epiR)       # Calculadora epidemiológica profesional

print("✅ Entorno listo. Comencemos.")
## [1] "✅ Entorno listo. Comencemos."

2. Prevalencia (La Fotografía)

Concepto: Es la proporción de la población que tiene el evento en un momento (Punto) o periodo específico. No mide riesgo, mide la carga de enfermedad en la comunidad.

Ejercicio 1: Encuesta de Diabetes

Imaginemos que realizamos una encuesta rápida a 20 pacientes en la sala de espera.

  • 0 = Sano
  • 1 = Enfermo (Caso prevalente)

Calcularemos la prevalencia puntual y su intervalo de confianza al 95%.

# --- EJERCICIO 1 CORREGIDO: CÁLCULO DE PREVALENCIA ---

# 1. Creamos los datos de la encuesta (Simulación)
datos_encuesta <- tibble(
  id_paciente = 1:20,
  diabetes = c(0, 1, 0, 0, 1, 1, 0, 0, 0, 0, 
               0, 1, 0, 0, 0, 0, 1, 0, 0, 0)
)

# 2. Preparamos los insumos (Numerador y Denominador)
num_casos <- sum(datos_encuesta$diabetes)
poblacion_total <- nrow(datos_encuesta)

# 3. Cálculo Manual (Puntual)
prevalencia <- num_casos / poblacion_total
print(paste("La Prevalencia de Punto es:", prevalencia * 100, "%"))
## [1] "La Prevalencia de Punto es: 25 %"
# 4. Cálculo del Intervalo de Confianza con epiR (CORREGIDO)
# epi.conf necesita una matriz de 1 fila y 2 columnas: c(casos, total)
matriz_datos <- matrix(c(num_casos, poblacion_total), nrow = 1, ncol = 2)

# Ahora sí ejecutamos la función
resultado_epi <- epi.conf(matriz_datos, ctype = "prop.single")

# Mostramos el resultado (est = estimación, lower = límite inf, upper = límite sup)
print(resultado_epi)
##   est   se      lower     upper
## 1 0.2 0.08 0.08860585 0.3913095
print(paste("Prevalencia con IC 95%:", 
            round(resultado_epi$est * 100, 1), "% (",
            round(resultado_epi$lower * 100, 1), "-", 
            round(resultado_epi$upper * 100, 1), ")"))
## [1] "Prevalencia con IC 95%: 20 % ( 8.9 - 39.1 )"

3. Incidencia Acumulada (Riesgo) y Odds - Cohorte Cerrada

Concepto de Riesgo: La probabilidad de que ocurra un evento en un periodo determinado. El denominador es el total de personas en riesgo al inicio. Este cálculo asume que la población es fija (nadie entra, nadie sale y todos son seguidos por el mismo tiempo). Concepto de Odds: Es la razón entre la probabilidad de que el evento ocurra y la probabilidad de que no ocurra. El denominador son las personas que no tuvieron el evento.

Ejercicio 2: El Estudio de la Aspirina (NEJM 1989)

Utilizaremos los datos agregados del famoso Physicians’ Health Study, una cohorte cerrada de 22,071 médicos. Calcularemos el riesgo y la “odds” para cada uno por separado para entender su diferencia matemática.

# --- EJERCICIO 2: RIESGO VS ODDS (Aspirina) ---

# 1. Definimos los datos del estudio
casos_aspirina <- 139
n_aspirina <- 11037
sanos_aspirina <- n_aspirina - casos_aspirina

casos_placebo <- 239
n_placebo <- 11034
sanos_placebo <- n_placebo - casos_placebo

# 2. Cálculo de Incidencia Acumulada (Riesgo)
# Fórmula: Casos / Total
riesgo_aspirina <- casos_aspirina / n_aspirina
riesgo_placebo <- casos_placebo / n_placebo

# 3. Cálculo de Odds (Posibilidad)
# Fórmula: Casos / Sanos
odds_aspirina <- casos_aspirina / sanos_aspirina
odds_placebo <- casos_placebo / sanos_placebo

# 4. Resultados para el grupo Aspirina
print(paste("GRUPO ASPIRINA:"))
## [1] "GRUPO ASPIRINA:"
print(paste("Riesgo (Probabilidad):", round(riesgo_aspirina * 100, 3), "%"))
## [1] "Riesgo (Probabilidad): 1.259 %"
print(paste("Odds (Posibilidad):", round(odds_aspirina, 4)))
## [1] "Odds (Posibilidad): 0.0128"
# 5. Resultados para el grupo Placebo
print(paste("GRUPO PLACEBO:"))
## [1] "GRUPO PLACEBO:"
print(paste("Riesgo (Probabilidad):", round(riesgo_placebo * 100, 3), "%"))
## [1] "Riesgo (Probabilidad): 2.166 %"
print(paste("Odds (Posibilidad):", round(odds_placebo, 4)))
## [1] "Odds (Posibilidad): 0.0221"
# --- REFLEXIÓN PEDAGÓGICA ---
# Note que cuando el evento es raro (frecuencia < 10%), el Riesgo y el Odds
# son numéricamente muy similares. Sin embargo, conceptualmente son distintos:
# El riesgo divide entre 'todos', el odds divide entre 'los que no enfermaron'.

4. Tasa de Incidencia (Densidad) - Cohorte Dinámica

Concepto: La velocidad con la que aparecen nuevos casos. Aquí el denominador ya no es “personas”, sino Tiempo-Persona. Es la medida vital cuando hay pérdidas de seguimiento (datos censurados) o tiempos de ingreso variables.

Ejercicio 3: Cohorte Cardiología Rosales

Trabajaremos con una cohorte simulada de 50 pacientes post-infarto.

Cálculo de Tasa Calcularemos los años-persona exactos restando la fecha de ingreso de la fecha de último control.

# --- EJERCICIO 3: CÁLCULO DE TASA DE INCIDENCIA ---

# 1. Cargar los datos
datos_cardio <- read_csv("cohorte_cardiologia_rosales.csv")
## Rows: 50 Columns: 4
## ── Column specification ────────────────────────────────────────────────────────
## Delimiter: ","
## dbl  (2): id, evento_infarto
## date (2): fecha_ingreso, fecha_ultimo_control
## 
## ℹ Use `spec()` to retrieve the full column specification for this data.
## ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message.
# 2. Paso Crítico: Construir la variable Tiempo (Años-Persona)
# Usamos lubridate para restar fechas y convertir a años
datos_cardio <- datos_cardio %>%
  mutate(
    dias_riesgo = as.numeric(fecha_ultimo_control - fecha_ingreso),
    anios_riesgo = dias_riesgo / 365.25
  )

# Veamos los primeros 5 pacientes para entender qué hicimos
print(head(datos_cardio))
## # A tibble: 6 × 6
##      id fecha_ingreso fecha_ultimo_control evento_infarto dias_riesgo
##   <dbl> <date>        <date>                        <dbl>       <dbl>
## 1     1 2021-07-31    2021-12-20                        0         142
## 2     2 2021-07-02    2022-11-06                        1         492
## 3     3 2021-07-10    2023-07-26                        0         746
## 4     4 2021-11-30    2024-01-04                        0         765
## 5     5 2020-09-11    2022-02-05                        0         512
## 6     6 2021-09-12    2023-07-08                        0         664
## # ℹ 1 more variable: anios_riesgo <dbl>
# 3. Sumar el Numerador (Eventos) y el Denominador (Tiempo)
total_eventos <- sum(datos_cardio$evento_infarto)
total_tiempo_anios <- sum(datos_cardio$anios_riesgo)
total_pacientes <- nrow(datos_cardio)

print(paste("Total Eventos (Numerador):", total_eventos))
## [1] "Total Eventos (Numerador): 14"
print(paste("Total Años-Persona (Denominador):", round(total_tiempo_anios, 2)))
## [1] "Total Años-Persona (Denominador): 65.26"
# 4. Cálculo de la Tasa de Incidencia (TI)
# Fórmula: Eventos / Tiempo-Persona Total
tasa_incidencia <- total_eventos / total_tiempo_anios

print(paste("Tasa de Incidencia:", round(tasa_incidencia, 4), "eventos por año-persona"))
## [1] "Tasa de Incidencia: 0.2145 eventos por año-persona"
print(paste("Interpretación: Ocurren", round(tasa_incidencia * 100, 1), 
            "infartos por cada 100 años-persona de seguimiento."))
## [1] "Interpretación: Ocurren 21.5 infartos por cada 100 años-persona de seguimiento."
# 5. COMPARACIÓN: ¿Qué pasaría si usamos la fórmula incorrecta (Riesgo)?
# (El error ingenuo de dividir entre el N inicial)
riesgo_ingenuo <- total_eventos / total_pacientes

print("--- MOMENTO DE REFLEXIÓN ---")
## [1] "--- MOMENTO DE REFLEXIÓN ---"
print(paste("Cálculo Incorrecto (Riesgo Ingenuo):", riesgo_ingenuo * 100, "%"))
## [1] "Cálculo Incorrecto (Riesgo Ingenuo): 28 %"
print(paste("Cálculo Correcto (Tasa x 100 años-persona):", round(tasa_incidencia * 100, 1)))
## [1] "Cálculo Correcto (Tasa x 100 años-persona): 21.5"
# Note la diferencia. En cohortes dinámicas, el riesgo ingenuo suele fallar.

IMPORTANTE: No es que esperemos 100 años para ver los 25 infartos. Es que si juntamos el tiempo de todos los pacientes, al acumular 100 años-persona, esperaríamos ver esa cantidad de eventos.


5. Relación entre Prevalencia e Incidencia (\(P \approx I \times D\))

Concepto: Imagine un lavabo (o una bañera).

  • El grifo que vierte agua es la Incidencia (\(I\)): casos nuevos.
  • El nivel de agua estancada es la Prevalencia (\(P\)): casos existentes.
  • El desagüe es la salida (Cura o Muerte). Cuanto más pequeño es el desagüe, más tiempo permanece el agua (Duración, \(D\)).

La Fórmula de Oro: En una población estable y para enfermedades con prevalencia baja, la relación matemática es:

\[ Prevalencia \approx Incidencia \times Duración \]

Ejercicio 4: La Paradoja de Salud Pública

Vamos a simular dos enfermedades en R para demostrar cómo una enfermedad con menos contagios puede tener más enfermos totales llenando el hospital.

  • Enfermedad A (Gripe): Muy contagiosa (Alta Incidencia), pero dura poco (Baja Duración).
  • Enfermedad B (Diabetes): Menos casos nuevos (Baja Incidencia), pero es crónica (Alta Duración).
# --- EJERCICIO 4: SIMULACIÓN P = I x D ---

# 1. Definimos las variables
# Incidencia anual (casos por persona-año)
incidencia_gripe <- 0.20     # 20% de riesgo anual (Muy alto)
incidencia_diabetes <- 0.01  # 1% de riesgo anual (Bajo)

# Duración de la enfermedad (en años)
# Gripe: dura 1 semana (1/52 de un año)
duracion_gripe <- 1 / 52     
# Diabetes: dura 25 años promedio
duracion_diabetes <- 25      

# 2. Calculamos la Prevalencia estimada (P = I * D)
prevalencia_gripe <- incidencia_gripe * duracion_gripe
prevalencia_diabetes <- incidencia_diabetes * duracion_diabetes

# 3. Resultados
print(paste("Prevalencia Gripe:", round(prevalencia_gripe * 100, 2), "%"))
## [1] "Prevalencia Gripe: 0.38 %"
print(paste("Prevalencia Diabetes:", round(prevalencia_diabetes * 100, 2), "%"))
## [1] "Prevalencia Diabetes: 25 %"
# --- REFLEXIÓN CLÍNICA ---
# Observe los resultados:
# La Gripe tiene una incidencia 20 VECES MAYOR que la Diabetes.
# Sin embargo, la Diabetes tiene una carga (Prevalencia) 
# ~65 VECES MAYOR que la Gripe.

# 4. Escenario: ¿Qué pasa si mejoramos el tratamiento de la Diabetes?
# El nuevo medicamento NO cura, pero evita que el paciente muera rápido.
# Esto aumenta la Duración (D).

nueva_duracion <- 35 # Ahora viven 35 años con la enfermedad (antes 25)

nueva_prevalencia <- incidencia_diabetes * nueva_duracion

print(paste("Prevalencia tras 'mejorar' el tratamiento:", 
            round(nueva_prevalencia * 100, 2), "%"))
## [1] "Prevalencia tras 'mejorar' el tratamiento: 35 %"
# Conclusión automática
if(nueva_prevalencia > prevalencia_diabetes) {
  print("CONCLUSIÓN PARADÓJICA: ¡El éxito médico aumentó la prevalencia!")
  print("Recordatorio: No confunda aumento de prevalencia con fracaso del programa de prevención.")
}
## [1] "CONCLUSIÓN PARADÓJICA: ¡El éxito médico aumentó la prevalencia!"
## [1] "Recordatorio: No confunda aumento de prevalencia con fracaso del programa de prevención."

Fin del Tutorial.

Guarde su script como Practica_Jornada2_Apellido.R