Modelo SEIR

El modelo SEIR es un modelo epidemiológico que divide a la población en cuatro compartimentos: Susceptibles (S), Expuestos (E), Infectados (I) y Recuperados (R). Este modelo es útil para enfermedades que tienen un período de latencia durante el cual los individuos están expuestos pero no son infecciosos.

Ecuaciones diferenciales del modelo SEIR

Las ecuaciones diferenciales que describen el modelo SEIR son las siguientes: \[\begin{align*} \frac{dS}{dt} & = -\beta \frac{S I}{N} \\ \frac{dE}{dt} & = \beta \frac{S I}{N} - \sigma E \\ \frac{dI}{dt} & = \sigma E - \gamma I \\ \frac{dR}{dt} & = \gamma I \end{align*}\].

donde:

  • \(S\): Número de individuos susceptibles.
  • \(E\): Número de individuos expuestos.
  • \(I\): Número de individuos infectados.
  • \(R\): Número de individuos recuperados.
  • \(N\): Población total (constante).
  • \(\beta\): Tasa de transmisión.
  • \(\sigma\): Tasa de progresión de expuestos a infectados (inversa del período de latencia).
  • \(\gamma\): Tasa de recuperación (inversa del periodo infeccioso).

Implementación en R

A continuación, implementaremos el modelo SEIR en R utilizando el paquete deSolve para resolver las ecuaciones diferenciales.

# Install if needed: install.packages("deSolve")
library(deSolve)
# para graficar
library(ggplot2)
library(tidyr)

# SEIR model function
seir_model <- function(time, state, parameters) {
  with(as.list(c(state, parameters)), {
    N <- S + E + I + R
    
    dS <- -beta * S * I / N
    dE <- beta * S * I / N - sigma * E
    dI <- sigma * E - gamma * I
    dR <- gamma * I
    
    return(list(c(dS, dE, dI, dR)))
  })
}

# Parameters
parameters <- c(
  beta = 0.5,      # transmission rate
  sigma = 1/5.2,   # 1/latent period (5.2 days for COVID-19)
  gamma = 1/10     # 1/infectious period (10 days)
)

# Initial state
N <- 1
initial_state <- c(
  S = N - 0.001,
  E = 0.0005,
  I = 0.0005,
  R = 0
)

# Time vector (days)
times <- seq(0, 180, by = 1)

# Solve ODE
output <- ode(y = initial_state, times = times, func = seir_model, parms = parameters)

# Convert to data frame
output_df <- as.data.frame(output)

# Reshape data for ggplot
output_long <- output_df %>%
  pivot_longer(cols = c(S, E, I, R), names_to = "Compartimento", values_to = "Count")

# Plot
ggplot(output_long, aes(x = time, y = Count, color = Compartimento)) +
  geom_line(linewidth = 1.2) +
  scale_color_manual(values = c("S" = "blue", "E" = "orange", "I" = "red", "R" = "green")) +
  labs(x = "Tiempo (días)", y = "Fracción de Individuos") +
  theme_minimal() +
  theme(legend.position = "right")

Figura 1. Dinámica del modelo SEIR mostrando las fracciones de individuos en cada compartimento a lo largo del tiempo.

EJERCICIO 1: Modifique los parámetros del modelo (β, σ, γ) y observe cómo afectan la dinámica de la enfermedad. ¿Qué sucede si aumenta la tasa de transmisión β? ¿Y si disminuye la tasa de recuperación γ?

Métricas de la epidemia

A continuación calcularemos algunas métricas claves de las epidemias:

  • Número máximo de individuos infecciosos simultáneamente (\(I_{max}\)): pico de I en la curva de infectados.
  • Día en el que ocurre el máximo de infecciones (\(t_{Imax}\)): obtenido a partir de \(I_{max}\)
  • Número de susceptibles en el pico (\(S_{Imax}\)).
  • Número básico de reproducción (\(R_0\)):
    \[R_0 = \frac{\beta}{\gamma}\]
  • Umbral de inmunidad de rebaño (\(UIR\)):
    \[UIR = 1 - \frac{1}{R_0}\]
  • Susceptibles en UIR (\(S_{UIR}\)):
    \[S_{UIR} = N*(1 - UIR)\]
  • Tamaño final de la epidemia (\(R_{\infty}\))
  • Tasa de ataque (Incidencia Proporcional) (\(TdA\)):
    \[TdA = \frac{R_{\infty}}{N}\]

Cálculo de métricas epidemiológicas

Las cantidades de individuos están expresadas en fracciones de la población total N.

# 1. Maximum number of infectious individuals (I_max)
I_max <- max(output_df$I)

# 2. Time when peak occurs
time_peak <- output_df$time[which.max(output_df$I)]

# 3. Susceptible population at peak (S at peak)
S_at_peak <- output_df$S[which.max(output_df$I)]

# 4. Herd immunity threshold (theoretical)
R0 <- parameters["beta"] / parameters["gamma"]
HIT_theoretical <- 1 - (1 / R0)  # Herd Immunity Threshold
S_threshold_theoretical <- N * (1 - HIT_theoretical)  # Susceptibles at HIT

# 5. Final epidemic size (proportion infected)
final_R <- tail(output_df$R, 1)
attack_rate <- final_R / N

Tabla de métricas epidemiológicas básica

## ==================================================
## TABLA 1. Métricas Epidemiológicas del Modelo SEIR
## ==================================================
## Tamaño de la Población (N): 1
## Número básico de reproducción (R_0): 5
## --- Dinámica del Modelo---
## Pico de infecciones (I_max): 0.301 individuos
## Tiempo hasta el pico: 50 días
## Suceptibles en el pico (S_Imax): 0.123 individuos
## --- Umbral de Inmunidad de Rebaño ---
## Valor teórico de UIR: 80 %
## Fracción de S_UIR: 0.2 individuos
## --- Tamaño final de la Epidemia ---
## Infectados totales (attack rate): 99.302 %
## Recuperados finales: 0.993 individuos
## Suceptibles finales: 0.007 individuos
## ===============================================

Tabla de métricas epidemiológicas con gt

# Instalar si es necesario: install.packages("gt")
library(gt)
library(dplyr)

# Crear data frame con las métricas
tabla_metricas <- data.frame(
  Categoría = c(
    "Parámetros Poblacionales",
    "Parámetros Poblacionales",
    "",
    "Dinámica del Modelo",
    "Dinámica del Modelo",
    "Dinámica del Modelo",
    "",
    "Umbral de Inmunidad de Rebaño",
    "Umbral de Inmunidad de Rebaño",
    "",
    "Tamaño Final de la Epidemia",
    "Tamaño Final de la Epidemia",
    "Tamaño Final de la Epidemia"
  ),
  Métrica = c(
    "Tamaño de la Población (N)",
    "Número básico de reproducción (R₀)",
    "",
    "Pico de infecciones (I_max)",
    "Tiempo hasta el pico",
    "Susceptibles en el pico (S_Imax)",
    "",
    "Valor teórico de UIR",
    "Fracción de S_UIR",
    "",
    "Infectados totales (attack rate)",
    "Recuperados finales",
    "Susceptibles finales"
  ),
  Valor = c(
    format(N, big.mark = ","),
    round(R0, 2),
    "",
    format(round(I_max, 3), big.mark = ","),
    time_peak,
    format(round(S_at_peak, 3), big.mark = ","),
    "",
    paste0(round(HIT_theoretical * 100, 3), "%"),
    format(round(S_threshold_theoretical, 3), big.mark = ","),
    "",
    paste0(round(attack_rate * 100, 3), "%"),
    format(round(final_R, 3), big.mark = ","),
    format(round(tail(output_df$S, 1), 3), big.mark = ",")
  ),
  Unidad = c(
    "individuos",
    "adimensional",
    "",
    "individuos",
    "días",
    "individuos",
    "",
    "porcentaje",
    "individuos",
    "",
    "porcentaje",
    "individuos",
    "individuos"
  )
)

# Crear tabla con gt
tabla_gt <- tabla_metricas %>%
  filter(Categoría != "") %>%  # Eliminar filas vacías
  gt() %>%
  tab_header(
    title = md("**TABLA 1. Métricas Epidemiológicas del Modelo SEIR**"),
    subtitle = "Resultados de la simulación determinística"
  ) %>%
  tab_row_group(
    label = "Tamaño Final de la Epidemia",
    rows = Categoría == "Tamaño Final de la Epidemia"
  ) %>%
  tab_row_group(
    label = "Umbral de Inmunidad de Rebaño",
    rows = Categoría == "Umbral de Inmunidad de Rebaño"
  ) %>%
  tab_row_group(
    label = "Dinámica del Modelo",
    rows = Categoría == "Dinámica del Modelo"
  ) %>%
  tab_row_group(
    label = "Parámetros Poblacionales",
    rows = Categoría == "Parámetros Poblacionales"
  ) %>%
  cols_hide(columns = Categoría) %>%
  cols_label(
    Métrica = "Métrica",
    Valor = "Valor",
    Unidad = "Unidad"
  ) %>%
  cols_align(
    align = "left",
    columns = Métrica
  ) %>%
  cols_align(
    align = "right",
    columns = c(Valor, Unidad)
  ) %>%
  tab_style(
    style = cell_text(weight = "bold"),
    locations = cells_column_labels()
  ) %>%
  tab_style(
    style = cell_fill(color = "#E8F4F8"),
    locations = cells_row_groups()
  ) %>%
  tab_style(
    style = cell_text(weight = "bold", size = px(13)),
    locations = cells_row_groups()
  ) %>%
  tab_options(
    table.font.size = px(12),
    heading.title.font.size = px(16),
    heading.subtitle.font.size = px(13),
    row_group.padding = px(8),
    table.border.top.style = "solid",
    table.border.bottom.style = "solid",
    row_group.border.top.style = "solid",
    row_group.border.bottom.style = "solid"
  ) %>%
  tab_source_note(
    source_note = md("*Nota: R₀ = β/γ; UIR = Umbral de Inmunidad de Rebaño*; individuos: fracción de N")
  )

# Mostrar tabla
tabla_gt
TABLA 1. Métricas Epidemiológicas del Modelo SEIR
Resultados de la simulación determinística
Métrica Valor Unidad
Parámetros Poblacionales
Tamaño de la Población (N) 1 individuos
Número básico de reproducción (R₀) 5 adimensional
Dinámica del Modelo
Pico de infecciones (I_max) 0.301 individuos
Tiempo hasta el pico 50 días
Susceptibles en el pico (S_Imax) 0.123 individuos
Umbral de Inmunidad de Rebaño
Valor teórico de UIR 80% porcentaje
Fracción de S_UIR 0.2 individuos
Tamaño Final de la Epidemia
Infectados totales (attack rate) 99.302% porcentaje
Recuperados finales 0.993 individuos
Susceptibles finales 0.007 individuos
Nota: R₀ = β/γ; UIR = Umbral de Inmunidad de Rebaño; individuos: fracción de N