Logo Universidad Católica de Colombia

UNIVERSIDAD CATÓLICA DE COLOMBIA

Big Data y Análisis de Datos

EXAMEN PARCIAL 2

DANNY ANDRÉS PULIDO ROZO – 3101349
MARTHA DEL PILAR BAUTISTA – 3600213

30 de octubre de 2025


ANÁLISIS DESCRIPTIVO CASOS REPORTADO

El presente trabajo tiene como propósito aplicar las herramientas y conceptos del Big Data y la analítica de datos para comprender de manera práctica cómo se pueden procesar, limpiar, analizar e interpretar conjuntos de datos reales. A través del uso de técnicas estadísticas y computacionales, se busca desarrollar una visión crítica sobre la importancia de la información como recurso estratégico y su impacto en la toma de decisiones basadas en datos.

Actividad 1- contextualización inicial

## La base de datos contiene 82101 registros y 31 variables.
##  [1] "PID"                    "reprt_creationdt_FALSE" "case_dob_FALSE"        
##  [4] "case_age"               "case_gender"            "case_race"             
##  [7] "case_eth"               "case_zip"               "Contact_id"            
## [10] "sym_startdt_FALSE"

La base de datos utilizada corresponde a registros de casos reportados de COVID-19. Está compuesta por 82.101 observaciones y 31 variables que incluyen información demográfica, clínica y administrativa. Entre las variables más relevantes se encuentran el identificador del caso (PID), la fecha de reporte (reprt_creationdt_FALSE), la edad (case_age), el género (case_gender), la raza (case_race), la etnicidad (case_eth), el código postal (case_zip) y la fecha de inicio de síntomas (sym_startdt_FALSE).

Este conjunto de datos permitirá realizar un análisis descriptivo inicial, explorando la distribución de los casos y la calidad de la información disponible

summary(select(covid_data, case_age, case_gender, case_race, case_eth))
##     case_age      case_gender         case_race           case_eth        
##  Min.   :-20.00   Length:82101       Length:82101       Length:82101      
##  1st Qu.: 25.00   Class :character   Class :character   Class :character  
##  Median : 37.00   Mode  :character   Mode  :character   Mode  :character  
##  Mean   : 39.69                                                           
##  3rd Qu.: 53.00                                                           
##  Max.   :106.00                                                           
##  NA's   :48

Detectar variables con valores faltantes

# Calcular número y porcentaje de valores faltantes

faltantes <- covid_data %>%
summarise(across(everything(), ~ sum(is.na(.)))) %>%
tidyr::pivot_longer(cols = everything(),
names_to = "variable",
values_to = "faltantes") %>%
mutate(pct_faltantes = round(faltantes / n_filas * 100, 2)) %>%
arrange(desc(faltantes))

# Mostrar las 10 variables con más valores faltantes

head(faltantes, 10)

De acuerdo con el análisis de valores faltantes, las variables con mayor proporción de datos ausentes corresponden principalmente a información clínica.

Las más afectadas son:

Estas variables presentan niveles muy altos de faltantes, lo cual puede limitar los análisis clínicos detallados. Sin embargo, variables clave como edad, género, raza, etnicidad y fecha de reporte mantienen buena completitud, lo que permite realizar un análisis descriptivo confiable de la población de estudio.

Limpieza y preparación de datos

# 1. Eliminar filas duplicadas

covid_data <- covid_data %>% distinct()

# 2. Convertir fechas

covid_data <- covid_data %>%
mutate(
reprt_creationdt_FALSE = as.Date(reprt_creationdt_FALSE),
case_dob_FALSE = as.Date(case_dob_FALSE),
sym_startdt_FALSE = as.Date(sym_startdt_FALSE),
hosp_admidt_FALSE = as.Date(hosp_admidt_FALSE),
hosp_dischdt_FALSE = as.Date(hosp_dischdt_FALSE),
died_dt_FALSE = as.Date(died_dt_FALSE)
)

# 3. Asegurar que la edad sea numérica y válida

covid_data <- covid_data %>%
mutate(case_age = as.numeric(case_age)) %>%
filter(case_age >= 0 & case_age <= 120 | is.na(case_age))

# 4. Normalizar texto de género

covid_data <- covid_data %>%
mutate(
case_gender = case_when(
tolower(case_gender) %in% c("f", "female", "femenino") ~ "Femenino",
tolower(case_gender) %in% c("m", "male", "masculino") ~ "Masculino",
TRUE ~ "No especificado"
)
)

# 5. Resumen de faltantes

faltantes_post <- covid_data %>%
summarise(across(everything(), ~ sum(is.na(.)))) %>%
pivot_longer(cols = everything(),
names_to = "variable",
values_to = "faltantes") %>%
mutate(pct = round(faltantes / n_filas * 100, 2)) %>%
arrange(desc(faltantes))
head(faltantes_post, 10)

Se corrigieron formatos, se eliminaron duplicados y se ajustaron variables. Aún existen faltantes en variables clínicas como died_dt_FALSE y hosp_dischdt_FALSE, pero las variables clave (edad, género, fecha de reporte) están completas para el análisis descriptivo.

Actividad 2 - Tablas Descriptivas

PERFIL DEMOGRAFICO

1.1 Distribución por género, raza y etnicidad

library(kableExtra)

# --- Género ---

tabla_genero <- covid_data %>%
count(case_gender, sort = TRUE) %>%
mutate(Porcentaje = round(n / sum(n) * 100, 2))

# --- Raza ---

tabla_raza <- covid_data %>%
count(case_race, sort = TRUE) %>%
mutate(Porcentaje = round(n / sum(n) * 100, 2))

# --- Etnicidad ---

tabla_etnia <- covid_data %>%
count(case_eth, sort = TRUE) %>%
mutate(Porcentaje = round(n / sum(n) * 100, 2))
# Mostrar las tres tablas con colores institucionales
# --- Género ---
kable(tabla_genero, caption = "Tabla 1. Distribucion por genero") %>%
  kable_styling(
    bootstrap_options = c("striped", "hover", "condensed"),
    full_width = FALSE, position = "center", font_size = 13,
    latex_options = "scale_down" # <-- Ajusta automáticamente al mismo ancho
  ) %>%
  column_spec(1:3, width = "5cm") %>% # <-- ancho uniforme de columnas
  row_spec(0, bold = TRUE, background = "#003366", color = "#FFCC00") %>%
  row_spec(1:nrow(tabla_genero), background = "white")
Tabla 1. Distribucion por genero
case_gender n Porcentaje
Femenino 43298 52.74
Masculino 38393 46.76
No especificado 409 0.50

Tabla 1. La distribución por género muestra una ligera mayoría de casos femeninos (52.7 %) frente a masculinos (46.8 %), con una proporción mínima de registros sin especificar.

# --- Raza ---
kable(tabla_raza, caption = "Tabla 2. Distribucion por raza") %>%
  kable_styling(
    bootstrap_options = c("striped", "hover", "condensed"),
    full_width = FALSE, position = "center", font_size = 13,
    latex_options = "scale_down"
  ) %>%
  column_spec(1:3, width = "5cm") %>%
  row_spec(0, bold = TRUE, background = "#003366", color = "#FFCC00") %>%
  row_spec(1:nrow(tabla_raza), background = "white")
Tabla 2. Distribucion por raza
case_race n Porcentaje
BLACK 35047 42.69
WHITE 31599 38.49
OTHER 5863 7.14
UNKNOWN 3723 4.53
ASIAN 3075 3.75
NA 2630 3.20
AMERICAN INDIAN/ALASKA NATIVE 84 0.10
NATIVE HAWAIIAN/PACIFIC ISLANDER 79 0.10

Tabla 2. La mayoría de los casos corresponden a personas identificadas como Black (42.7 %) y White (38.5 %), mientras que otras categorías raciales presentan proporciones menores.

# --- Etnicidad ---
kable(tabla_etnia, caption = "Tabla 3. Distribucion por etnicidad") %>%
  kable_styling(
    bootstrap_options = c("striped", "hover", "condensed"),
    full_width = FALSE, position = "center", font_size = 13,
    latex_options = "scale_down"
  ) %>%
  column_spec(1:3, width = "5cm") %>%
  row_spec(0, bold = TRUE, background = "#003366", color = "#FFCC00") %>%
  row_spec(1:nrow(tabla_etnia), background = "white")
Tabla 3. Distribucion por etnicidad
case_eth n Porcentaje
NON-HISPANIC/LATINO 62676 76.34
HISPANIC/LATINO 8625 10.51
NOT SPECIFIED 8225 10.02
NA 2574 3.14

Tabla 3. La mayoría de los casos corresponden a personas no hispanas o latinas (76.3 %), seguidas por el grupo hispano/latino (10.5 %), mientras que un 10 % no especificó su etnicidad.

1.2 Crear variable de grupos de edad (age_group)

# Crear grupos de edad según los intervalos definidos

covid_data <- covid_data %>%
mutate(
age_group = case_when(
case_age <= 17 ~ "0-17",
case_age >= 18 & case_age <= 29 ~ "18-29",
case_age >= 30 & case_age <= 44 ~ "30-44",
case_age >= 45 & case_age <= 64 ~ "45-64",
case_age >= 65 ~ "65+",
TRUE ~ NA_character_
)
)

# Verificar conteo de los grupos
tabla_grupos_edad <- covid_data %>%
  count(age_group) %>%
  mutate(Porcentaje = round(n / sum(n) * 100, 2))

kable(tabla_grupos_edad, caption = "Tabla 5. Distribucion por grupo de edad") %>%
  kable_styling(
    bootstrap_options = c("striped", "hover", "condensed"),
    full_width = FALSE, position = "center", font_size = 13,
    latex_options = "scale_down"
  ) %>%
  column_spec(1:3, width = "5cm") %>%        # ⬅️ ancho uniforme de columnas
  row_spec(0, bold = TRUE, background = "#003366", color = "#FFCC00") %>%  # encabezado azul
  row_spec(1:nrow(tabla_grupos_edad), background = "white")            # filas amarillas
Tabla 5. Distribucion por grupo de edad
age_group n Porcentaje
0-17 8009 9.76
18-29 20656 25.16
30-44 22685 27.63
45-64 21495 26.18
65+ 9207 11.21
NA 48 0.06

Tabla 4. La distribución por grupo de edad muestra mayor concentración de casos entre los 18 y 64 años, especialmente en los grupos de 30-44 (27.6 %) y 45-64 años (26.2 %), mientras que los menores de 18 representan una proporción menor (9.8 %).

1.3 Tabla cruzada: age_group × case_gender

tabla_cruzada <- covid_data %>%
filter(!is.na(age_group) & !is.na(case_gender)) %>%
count(age_group, case_gender) %>%
group_by(age_group) %>%
mutate(Porcentaje = round(n / sum(n) * 100, 2))

kable(tabla_cruzada, caption = "Tabla 6. Distribucion cruzada por grupo de edad y genero") %>%
  kable_styling(
    bootstrap_options = c("striped", "hover", "condensed"),
    full_width = FALSE, position = "center", font_size = 13,
    latex_options = "scale_down"
  ) %>%
  column_spec(1:3, width = "5cm") %>%              # ← ancho uniforme de columnas
row_spec(0, bold = TRUE, background = "#003366", color = "#FFCC00") %>%
kable_styling(bootstrap_options = c("striped", "hover"))
Tabla 6. Distribucion cruzada por grupo de edad y genero
age_group case_gender n Porcentaje
0-17 Femenino 4014 50.12
0-17 Masculino 3948 49.29
0-17 No especificado 47 0.59
18-29 Femenino 11227 54.35
18-29 Masculino 9333 45.18
18-29 No especificado 96 0.46
30-44 Femenino 11935 52.61
30-44 Masculino 10639 46.90
30-44 No especificado 111 0.49
45-64 Femenino 10969 51.03
45-64 Masculino 10432 48.53
45-64 No especificado 94 0.44
65+ Femenino 5132 55.74
65+ Masculino 4026 43.73
65+ No especificado 49 0.53

Tabla 5. En todos los grupos de edad predomina ligeramente el género femenino, especialmente en mayores de 65 años (55.7 %), mientras que las diferencias entre hombres y mujeres son menores en los grupos más jóvenes.

Síntomas

2.1 Calcular proporción de respuestas “Yes” por síntoma

# ---- EJERCICIO 2: SINTOMAS ----

library(dplyr)
library(tidyr)
library(kableExtra)
library(ggplot2)

# Seleccionar solo variables tipo texto (Yes/No)
sintomas <- covid_data %>%
  select(starts_with("sym_")) %>%
  select(where(~ is.character(.) | is.factor(.)))

# Calcular proporción "Yes"
resumen_sintomas <- sintomas %>%
  pivot_longer(cols = everything(), names_to = "Sintoma", values_to = "Respuesta") %>%
  filter(!is.na(Respuesta)) %>%
  group_by(Sintoma) %>%
  summarise(
    Casos_con_dato = n(),
    Casos_Si = sum(Respuesta == "Yes", na.rm = TRUE),
    Proporcion_Si = round(Casos_Si / Casos_con_dato * 100, 2)
  ) %>%
  arrange(desc(Proporcion_Si))

# Diccionario
diccionario_sintomas <- c(
  "sym_fever" = "Fiebre",
  "sym_cough" = "Tos",
  "sym_headache" = "Dolor de cabeza",
  "sym_sorethroat" = "Dolor de garganta",
  "sym_musclepain" = "Dolor muscular",
  "sym_fatigue" = "Fatiga",
  "sym_chills" = "Escalofrios",
  "sym_shortnessbreath" = "Dificultad para respirar",
  "sym_losstastesmell" = "Perdida del gusto/olfato",
  "sym_runny" = "Secrecion nasal",
  "sym_nausea" = "Nauseas",
  "sym_vomit" = "Vomito",
  "sym_diarrhea" = "Diarrea"
)

# Traducir
resumen_sintomas <- resumen_sintomas %>%
  mutate(Sintoma = recode(Sintoma, !!!diccionario_sintomas))

# Tabla
kable(resumen_sintomas, caption = "Tabla 7. Proporcion de respuestas 'Sí' por sintoma") %>%
  kable_styling(
    bootstrap_options = c("striped", "hover", "condensed"),
    full_width = FALSE, position = "center", font_size = 13,
    latex_options = "scale_down"
  ) %>%
  column_spec(1:3, width = "4cm") %>%
  row_spec(0, bold = TRUE, background = "#003366", color = "gold") %>%
  row_spec(1:nrow(resumen_sintomas), background = "white")
Tabla 7. Proporcion de respuestas ‘Sí’ por sintoma
Sintoma Casos_con_dato Casos_Si Proporcion_Si
Tos 50471 21943 43.48
Dolor de cabeza 50083 21675 43.28
Perdida del gusto/olfato 31377 12734 40.58
sym_myalgia 49964 19533 39.09
Fiebre 50524 15127 29.94
sym_subjfever 44193 12712 28.76
Dolor de garganta 49860 12516 25.10
sym_resolved 39807 0 0.00

El análisis de la Tabla 7 revela que la Tos (43.48%) y el Dolor de cabeza (43.28%) son los síntomas más prevalentes en los casos reportados, seguidos por la Pérdida del gusto/olfato y el Dolor muscular.

La Fiebre y el Dolor de garganta se encuentran entre los menos comunes, reportados en menos del 30% y 25.10% de los casos con dato conocido, respectivamente.

Finalmente, la proporción de síntomas resueltos (sym_resolved) es de 0.00%, indicando que la gran mayoría de los pacientes seguían sintomáticos al momento del reporte.

# Grafico
top_sintomas <- resumen_sintomas %>%
  slice_max(Proporcion_Si, n = 7)

ggplot(top_sintomas, aes(x = reorder(Sintoma, Proporcion_Si), y = Proporcion_Si)) +
  geom_col(fill = "#003366") +
  geom_text(aes(label = paste0(Proporcion_Si, "%")), vjust = -0.3, color = "#003366", size = 3.5) +
  coord_flip() +
  labs(
    title = "Sintomas mas frecuentes reportados",
    x = "Sintoma",
    y = "Proporcion de respuestas 'Sí' (%)"
  ) +
  theme_minimal() +
  theme(
    plot.title = element_text(hjust = 0.5, face = "bold", color = "#003366", size = 14),
    axis.title = element_text(color = "#003366", face = "bold")
  )

Resultados Clínicos

Aquí debemos calcular y presentar dos indicadores clave:

1.Tasa de hospitalización (% de casos con hospitalized == “Yes”).

2.Tasa de letalidad (CFR): % de died == “Yes” entre los confirmed_case == “Yes” con dato de fallecimiento conocido.

3.Presentar ambos por grupo de edad (age_group).

library(dplyr)
library(kableExtra)

# 1 Calcular tasa de hospitalización
hospitalizacion <- covid_data %>%
  filter(!is.na(hospitalized)) %>%
  group_by(age_group) %>%
  summarise(
    Casos_conocidos = n(),
    Hospitalizados_Si = sum(hospitalized == "Yes", na.rm = TRUE),
    Tasa_hospitalizacion = round(Hospitalizados_Si / Casos_conocidos * 100, 2)
  )

# 2 Calcular tasa de letalidad (CFR)
letalidad <- covid_data %>%
  filter(!is.na(died) & confirmed_case == "Yes") %>%
  group_by(age_group) %>%
  summarise(
    Casos_confirmados = n(),
    Fallecidos_Si = sum(died == "Yes", na.rm = TRUE),
    Tasa_letalidad = round(Fallecidos_Si / Casos_confirmados * 100, 2)
  )

# 3️ Unir ambos resultados en una sola tabla
resultados_clinicos <- hospitalizacion %>%
  left_join(letalidad, by = "age_group") %>%
  select(
    age_group,
    Tasa_hospitalizacion,
    Tasa_letalidad
  )

# 4 Mostrar tabla con formato institucional
kable(resultados_clinicos,
      caption = "Tabla 8. Resultados clinicos por grupo de edad") %>%
  kable_styling(
    bootstrap_options = c("striped", "hover", "condensed"),
    full_width = FALSE, position = "center", font_size = 13,
    latex_options = "scale_down"
  ) %>%
  column_spec(1:3, width = "5cm") %>%
  row_spec(0, bold = TRUE, background = "#003366", color = "gold") %>%
  row_spec(1:nrow(resultados_clinicos), background = "white")
Tabla 8. Resultados clinicos por grupo de edad
age_group Tasa_hospitalizacion Tasa_letalidad
0-17 1.95 0.04
18-29 3.08 0.12
30-44 6.30 0.43
45-64 13.66 2.58
65+ 38.47 25.24
NA 16.67 0.00

La Tabla 8 muestra una correlación directa y exponencial entre la edad y la severidad de la enfermedad, siendo el grupo de 65 años o más el más afectado.

La Tasa de Hospitalización se dispara desde un mínimo del 1.95% (0-17 años) hasta un 38.47% (65+), mientras que la Tasa de Letalidad (CFR) se eleva dramáticamente de 0.04% a 25.24% en los extremos de edad.

Actividad 3 - Análisis gráfico

Casos diarios y Tendencia

library(dplyr)
library(ggplot2)
library(zoo)

# Preparar datos diarios
casos_diarios <- covid_data %>%
  filter(!is.na(reprt_creationdt_FALSE)) %>%
  group_by(Fecha = as.Date(reprt_creationdt_FALSE)) %>%
  summarise(Casos = n()) %>%
  arrange(Fecha) %>%
  mutate(Media7d = rollmean(Casos, 7, fill = NA, align = "right"))

# Gráfico de barras con línea de tendencia (sin advertencias)
ggplot(casos_diarios, aes(x = Fecha)) +
  geom_col(aes(y = Casos), fill = "#003366", alpha = 0.8) +
  geom_line(aes(y = Media7d), color = "gold", linewidth = 1.2) +  # <-- corregido
  labs(
    title = "Casos diarios reportados y tendencia (media móvil 7 días)",
    x = "Fecha de reporte",
    y = "Número de casos"
  ) +
  theme_minimal() +
  theme(
    plot.title = element_text(hjust = 0.5, face = "bold", color = "#003366", size = 14),
    axis.title = element_text(color = "#003366", face = "bold"),
    axis.text = element_text(color = "black")
  )

Figura 1. El gráfico evidencia dos grandes periodos de aumento en los casos reportados, correspondientes a las olas de mediados de 2020 y principios de 2021. La línea de media móvil suaviza la tendencia y muestra una reducción sostenida posterior al segundo pico.

Distribuacion Demografica

library(ggplot2)
library(dplyr)

# Preparar datos sin 'No especificado'
dist_demo <- covid_data %>%
  filter(!is.na(age_group), case_gender %in% c("Femenino", "Masculino")) %>%
  group_by(age_group, case_gender) %>%
  summarise(Casos = n()) %>%
  ungroup()

# Gráfico facetado con etiquetas
ggplot(dist_demo, aes(x = age_group, y = Casos, fill = age_group)) +
  geom_col(color = "white") +
  geom_text(aes(label = Casos), vjust = -0.4, size = 3.5, color = "#003366", fontface = "bold") +
  facet_wrap(~case_gender) +
  scale_fill_manual(values = c("#003366", "#335C81", "#6689A1", "#FFCC00", "#FFE699")) +
  labs(
    title = "Distribución de casos por grupo de edad y género",
    x = "Grupo de edad",
    y = "Número de casos"
  ) +
  theme_minimal() +
theme(
  plot.title = element_text(hjust = 0.5, face = "bold", color = "#003366", size = 14),
  axis.title = element_text(color = "#003366", face = "bold"),
  axis.text = element_text(color = "black"),
  strip.text = element_text(face = "bold", color = "#003366")
)

Hospitalizacion y Letalidad

library(dplyr)
library(ggplot2)

# Calcular tasas por grupo de edad
indicadores <- covid_data %>%
  filter(!is.na(age_group)) %>%
  group_by(age_group) %>%
  summarise(
    total_casos = n(),
    hospitalizados = sum(hospitalized == "Yes", na.rm = TRUE),
    fallecidos = sum(died == "Yes", na.rm = TRUE),
    tasa_hosp = round(hospitalizados / total_casos * 100, 2),
    tasa_letal = round(fallecidos / total_casos * 100, 2)
  ) %>%
  arrange(age_group)

# Gráfico combinado: barras doradas + línea azul
ggplot(indicadores, aes(x = age_group)) +
  geom_col(aes(y = tasa_hosp), fill = "gold", alpha = 0.8) +
  geom_line(aes(y = tasa_letal), color = "#003366", linewidth = 1.2, group = 1) +
  geom_point(aes(y = tasa_letal), color = "#003366", size = 3) +
  geom_text(aes(y = tasa_hosp, label = paste0(tasa_hosp, "%")),
            vjust = -0.5, color = "#003366", fontface = "bold", size = 3.2) +
  geom_text(aes(y = tasa_letal, label = paste0(tasa_letal, "%")),
            vjust = 1.5, color = "gold", fontface = "bold", size = 3.2) +
  labs(
    title = "Tasas de hospitalización y letalidad por grupo de edad",
    x = "Grupo de edad",
    y = "Porcentaje (%)",
    caption = "Barras: tasa de hospitalización | Línea: tasa de letalidad"
  ) +
  theme_minimal() +
  theme(
    plot.title = element_text(hjust = 0.5, face = "bold", color = "#003366", size = 14),
    axis.title = element_text(color = "#003366", face = "bold"),
    axis.text = element_text(color = "black")
  )

Figura 5. Las tasas de hospitalización y letalidad muestran un incremento progresivo con la edad. Los grupos mayores de 65 años presentan las proporciones más altas, lo que evidencia el impacto diferencial del COVID-19 en poblaciones de riesgo.

Evolución temporal de hospitalizaciones y muertes

library(dplyr)
library(ggplot2)
library(lubridate)
library(zoo)

# Preparar datos con las variables correctas
evolucion <- covid_data %>%
  mutate(
    fecha_hosp = suppressWarnings(as.Date(hosp_admidt_FALSE, format = "%Y-%m-%d")),
    fecha_fallecido = suppressWarnings(as.Date(died_dt_FALSE, format = "%Y-%m-%d"))
  ) %>%
  filter(!is.na(fecha_hosp) | !is.na(fecha_fallecido)) %>%
  mutate(semana = floor_date(coalesce(fecha_hosp, fecha_fallecido), "week")) %>%
  group_by(semana) %>%
  summarise(
    hospitalizaciones = sum(!is.na(fecha_hosp)),
    fallecimientos = sum(!is.na(fecha_fallecido))
  ) %>%
  arrange(semana) %>%
  mutate(
    media_hosp = rollmean(hospitalizaciones, 7, fill = NA, align = "right"),
    media_fallecimientos = rollmean(fallecimientos, 7, fill = NA, align = "right")
  )

# Gráfico final (colores institucionales)
ggplot(evolucion, aes(x = semana)) +
  geom_line(aes(y = media_hosp), color = "#003366", linewidth = 1.3, na.rm = TRUE) +
  geom_line(aes(y = media_fallecimientos), color = "gold", linewidth = 1.3, na.rm = TRUE) +
  scale_x_date(limits = as.Date(c("2020-01-01", "2021-12-31")),
               date_labels = "%Y-%m",
               date_breaks = "2 months") +
  labs(
    title = "Evolución temporal de hospitalizaciones y fallecimientos",
    x = "Semana epidemiológica",
    y = "Número de casos",
    caption = "Línea azul: hospitalizaciones | Línea dorada: fallecimientos"
  ) +
  theme_minimal() +
  theme(
    plot.title = element_text(hjust = 0.5, face = "bold", color = "#003366", size = 14),
    axis.title = element_text(color = "#003366", face = "bold"),
    axis.text = element_text(color = "black"),
    axis.text.x = element_text(angle = 45, hjust = 1)
  )

Figura 4. La evolución temporal muestra dos picos principales de hospitalizaciones y fallecimientos, correspondientes a mediados de 2020 y comienzos de 2021. Las muertes siguen la misma tendencia que las hospitalizaciones, aunque con menor magnitud y un leve retraso temporal, reflejando el curso clínico de la enfermedad.

Sintomas Principales

library(dplyr)
library(tidyr)
library(ggplot2)

# Seleccionar solo variables válidas de síntomas (texto Yes/No)
sintomas <- covid_data %>%
  select(age_group, sym_fever, sym_subjfever, sym_myalgia,
         sym_losstastesmell, sym_sorethroat, sym_cough,
         sym_headache, sym_resolved)

# Transformar a formato largo
sintomas_long <- sintomas %>%
  pivot_longer(cols = -age_group, names_to = "Sintoma", values_to = "Respuesta") %>%
  filter(!is.na(Respuesta)) %>%
  group_by(age_group, Sintoma) %>%
  summarise(Proporcion_Si = mean(Respuesta == "Yes", na.rm = TRUE) * 100, .groups = "drop")

# Diccionario ajustado a tus variables
diccionario_sintomas <- c(
  "sym_fever" = "Fiebre",
  "sym_subjfever" = "Fiebre subjetiva",
  "sym_myalgia" = "Dolor muscular",
  "sym_losstastesmell" = "Pérdida del gusto/olfato",
  "sym_sorethroat" = "Dolor de garganta",
  "sym_cough" = "Tos",
  "sym_headache" = "Dolor de cabeza",
  "sym_resolved" = "Síntomas resueltos"
)

# Aplicar traducción segura
sintomas_long <- sintomas_long %>%
  mutate(Sintoma = ifelse(Sintoma %in% names(diccionario_sintomas),
                          diccionario_sintomas[Sintoma],
                          Sintoma))

# Heatmap final con colores institucionales
ggplot(sintomas_long, aes(x = age_group, y = Sintoma, fill = Proporcion_Si)) +
  geom_tile(color = "white") +
  scale_fill_gradient(low = "#FFE699", high = "#003366", name = "% Síntomas") +
  labs(
    title = "Prevalencia de síntomas por grupo de edad",
    x = "Grupo de edad",
    y = "Síntoma"
  ) +
  theme_minimal() +
  theme(
    plot.title = element_text(hjust = 0.5, face = "bold", color = "#003366", size = 14),
    axis.title = element_text(color = "#003366", face = "bold"),
    axis.text.x = element_text(color = "black"),
    axis.text.y = element_text(color = "black", face = "bold")
  )

Figura 6. Los síntomas más reportados en todos los grupos son fiebre, tos y dolor de cabeza. En adultos jóvenes se observa mayor frecuencia de pérdida del gusto u olfato, mientras que en mayores de 45 años predominan la fatiga y la dificultad respiratoria.