Respuestas a Ejercicios Propuestos
Preparación para el Examen Práctico — TC2001B.601
Este documento contiene las respuestas a los ejercicios propuestos para la preparación del examen práctico del curso TC2001B.601 — Introducción a la Ciencia de Datos (Ene-Jun 2026). Todas las bases de datos se leen directamente desde internet para garantizar reproducibilidad.
1 Preparación del entorno
Cargamos las librerías necesarias. Todas las llamadas a library() se concentran al inicio.
2 Ejercicio 1 — Evolución de búsquedas de ChatGPT en México
- Elabore una gráfica de líneas en la cual pueda ver la evolución de las búsquedas en Google de ChatGPT en México. Los datos están en este enlace. La columna
semanamuestra la fecha del domingo con el que inicia cada semana;chat_gpt_mexicoes el índice de búsqueda (0 a 100). - Determine la semana en la cual se alcanzó el día con mayor búsquedas de ChatGPT.
- ¿En qué fechas se alcanzan los mínimos locales y qué información aporta?
2.1 Carga de datos y gráfica base
Código
chatgpt <- read_csv("https://raw.githubusercontent.com/JuveCampos/TC2001B.601-Ciencia-de-datos-ene-jun-2026/refs/heads/main/05_EXAMENES/preparacion_examen_practico/chatgpt.csv") %>%
filter(chat_gpt_mexico > 0) # Eliminamos los datos de cuando no existía ChatGPT
# Gráfica base de líneas con la evolución de las búsquedas
grafica_chatgpt <- chatgpt %>%
ggplot(aes(x = semana, y = chat_gpt_mexico)) +
geom_line(color = "#1e4c7d", linewidth = 0.7) +
geom_point(color = "#1e4c7d", size = 0.8) +
scale_x_date(date_breaks = "3 weeks", date_labels = "%Y-%m-%d") +
labs(
title = "Evolución de búsquedas de ChatGPT en México",
subtitle = "Índice de búsqueda semanal (0 = mínimo, 100 = máximo histórico)",
x = "Semana (fecha del domingo)",
y = "Índice de búsqueda",
caption = "Fuente: Google Trends"
) +
theme_minimal() +
theme(axis.text.x = element_text(angle = 90, hjust = 1, vjust = 0.5))
grafica_chatgpt2.2 Semana con el máximo de búsquedas
Código
| semana | chat_gpt_mexico |
|---|---|
| 2025-09-28 | 100 |
| 2025-10-19 | 100 |
Respuesta. Las dos semanas en las que se alcanzó el valor máximo (100) fueron la del 28 de septiembre de 2025 y la del 19 de octubre de 2025.
2.3 Identificación de mínimos locales (gráfica interactiva)
Código
ggplotly(grafica_chatgpt)Pase el cursor sobre cada punto para ver su fecha y valor.
Interpretación. Al inspeccionar los mínimos locales en la gráfica interactiva se observa que los picos hacia abajo tienden a caer en semanas que coinciden con:
- Diciembre (vacaciones de fin de año / Navidad).
- Semana Santa (marzo-abril).
- Periodos vacacionales de verano (julio).
Esto sugiere que las búsquedas de ChatGPT están asociadas con actividad escolar y laboral: cuando la gente está de vacaciones, baja el interés.
3 Ejercicio 2 — Crecimiento sexenal del PIB
El archivo crecimiento_presidente.csv contiene la tasa de crecimiento acumulado para los primeros 23 trimestres de cada sexenio (hasta el 2024T2). Con estos datos, replique la gráfica original incluyendo todas las etiquetas y usando colores similares.
Código
crecimiento <- read_csv("https://raw.githubusercontent.com/JuveCampos/TC2001B.601-Ciencia-de-datos-ene-jun-2026/refs/heads/main/05_EXAMENES/preparacion_examen_practico/crecimiento_presidente.csv")
# Mapeo de colores de la paleta usada en la gráfica original
colores_presidente <- c(
"verde oscuro" = "#2F4e43",
"azul claro" = "#97cce9",
"café" = "#98362e"
)
# Ordenamos a los presidentes en el orden cronológico (aparecen en el CSV)
crecimiento <- crecimiento %>%
mutate(etiqueta = factor(etiqueta, levels = etiqueta))
# Replicamos la gráfica de barras
grafica_crecimiento <- crecimiento %>%
ggplot(aes(x = etiqueta, y = crecimiento, fill = color)) +
geom_col(width = 0.7) +
geom_text(
aes(label = paste0(crecimiento, "%")),
vjust = -0.4, size = 4, fontface = "bold", family = "Ubuntu"
) +
scale_fill_manual(values = colores_presidente, guide = "none") +
scale_y_continuous(labels = scales::comma_format(suffix = "%"),
expand = expansion(mult = c(0, 0.1))) +
labs(
title = "Crecimiento sexenal del PIB",
subtitle = "Serie desestacionalizada y de tendencia ciclo.\nComparación primeros 23 trimestres de cada sexenio",
x = NULL,
y = NULL,
caption = "Elaborado por México, ¿Cómo vamos? con la serie desestacionalizada del PIB de INEGI"
) +
theme_minimal(base_size = 12) +
theme(
plot.title = element_text(face = "bold", size = 20, color = "#6552d3"),
plot.subtitle = element_text(color = "gray50"),
panel.grid.major = element_blank(),
axis.text.x = element_text(face = "bold"),
axis.line.x = element_line(),
text = element_text(family = "Ubuntu")
)
grafica_crecimientoInterpretación. El sexenio de CSG tuvo el mayor crecimiento acumulado en los primeros 23 trimestres (24.8%), seguido por EZPDL (20.6%). Los sexenios más recientes (FCH, EPN y AMLO) tuvieron crecimientos considerablemente menores, siendo AMLO el de menor crecimiento acumulado (4.5%).
4 Ejercicio 3 — Métricas por vendedor
Con los datos de ventas_tienda.csv:
- Calcula por vendedor: número de transacciones, ingreso total e ingreso promedio por transacción.
- Construye un gráfico de barras ordenado por ingreso total (
reorder()dentro delaes()). - Añade
geom_text()con etiqueta en formato numérico con separador de miles (prettyNum(x, big.mark = ",")). - Aplica
theme_minimal, título y caption con la fuente.
4.1 Cálculo de métricas
Código
ventas <- read_csv("https://raw.githubusercontent.com/JuveCampos/TC2001B.601-Ciencia-de-datos-ene-jun-2026/refs/heads/main/02_EJERCICIOS_PRACTICOS/Sesion%2002/archivos%20carga/Data/ventas_tienda.csv")
metricas_vendedor <- ventas %>%
group_by(vendedor) %>%
summarise(
n_transacciones = n(), # Número de renglones
ingreso_total = sum(cantidad * precio_unitario, na.rm = TRUE),
ingreso_prom = ingreso_total / n_transacciones
) %>%
arrange(desc(ingreso_total))
metricas_vendedor %>% kable(digits = 2)| vendedor | n_transacciones | ingreso_total | ingreso_prom |
|---|---|---|---|
| Ana Garcia | 5 | 5397.99 | 1079.60 |
| Pedro Martinez | 3 | 4029.96 | 1343.32 |
| Maria Rodriguez | 3 | 2096.00 | 698.67 |
| Carlos Lopez | 4 | 1507.28 | 376.82 |
4.2 Gráfico de barras
Código
grafica_vendedores <- metricas_vendedor %>%
ggplot(aes(x = reorder(vendedor, -ingreso_total), y = ingreso_total)) +
geom_col(fill = "#1e4c7d") +
geom_text(
aes(label = prettyNum(round(ingreso_total), big.mark = ",")),
vjust = -0.4, size = 4
) +
scale_y_continuous(
labels = label_number(big.mark = ","),
expand = expansion(mult = c(0, 0.12))
) +
labs(
title = "Ingreso total por vendedor",
x = "Vendedor",
y = "Ingreso total",
caption = "Fuente: Registros internos de ventas"
) +
theme_minimal()
grafica_vendedores5 Ejercicio 4 — Conversión de Celsius a Fahrenheit
Fórmula: \(°F = \left(\frac{9}{5} \cdot °C\right) + 32\).
- Genere una función propia que le permita realizar la transformación.
- Obtenga a cuántos grados Fahrenheit equivalen 40 °C.
Código
[1] "40 °C equivalen a 104 °F"
Respuesta. 40 grados Celsius equivalen a 104 °F (calorcito).
6 Ejercicio 5 — Tiempo de traslado
Encuesta de 40 trabajadores en CDMX con el tiempo de traslado en minutos. Datos en tiempo_traslado.csv.
- Cargar los datos.
- Calcular media, mediana, mínimo y máximo (con
na.rm = TRUE). - Identificar y manejar los NAs.
- Detectar outliers con el método IQR: reportar Q1, Q3, IQR, límites e IDs.
- Generar un boxplot.
6.1 Carga y estadísticas descriptivas
Código
traslado <- read_csv("https://raw.githubusercontent.com/JuveCampos/TC2001B.601-Ciencia-de-datos-ene-jun-2026/refs/heads/main/05_EXAMENES/preparacion_examen_practico/tiempo_traslado.csv")
estadisticas_traslado <- traslado %>%
summarise(
media = mean(minutos, na.rm = TRUE),
mediana = median(minutos, na.rm = TRUE),
minimo = min(minutos, na.rm = TRUE),
maximo = max(minutos, na.rm = TRUE)
)
estadisticas_traslado %>% kable(digits = 2)| media | mediana | minimo | maximo |
|---|---|---|---|
| 43.68 | 36 | 2 | 180 |
Observación. El máximo (150 min) es mucho más grande que la media/mediana (~35–40 min), lo que sugiere la presencia de al menos un outlier alto. El mínimo (3 min) también parece muy pequeño para un traslado en CDMX (otro atípico, pero por abajo).
6.2 Manejo de NAs
Código
[1] "Número de NAs en la columna minutos: 2"
6.3 Detección de outliers con IQR
Código
[1] "Q1 = 31 | Q3 = 42 | IQR = 11"
[1] "Límite inferior = 14.5 | Límite superior = 58.5"
Código
| id | minutos |
|---|---|
| 2 | 3 |
| 7 | 150 |
| 16 | 2 |
| 20 | 180 |
| 37 | 3 |
| 40 | 155 |
Código
| id | minutos |
|---|---|
| 2 | 3 |
| 7 | 150 |
| 16 | 2 |
| 20 | 180 |
| 37 | 3 |
| 40 | 155 |
Respuesta. Los outliers son las observaciones cuyo valor cae fuera de \([Q_1 - 1.5 \cdot IQR,\; Q_3 + 1.5 \cdot IQR]\). Los IDs correspondientes aparecen en la tabla anterior. Estos registros podrían ser errores de captura o casos genuinos extremos que merecen análisis aparte.
6.4 Boxplot
Código
traslado_limpio %>%
ggplot(aes(y = minutos)) +
geom_boxplot(fill = "#1e4c7d", alpha = 0.7, outlier.color = "red") +
labs(
title = "Tiempo de traslado al trabajo (minutos)",
y = "Minutos",
caption = "Fuente: Encuesta a 40 trabajadores en CDMX"
) +
theme_minimal() +
theme(axis.text.x = element_blank(), axis.ticks.x = element_blank())7 Ejercicio 6 — Inversión pública y privada como % del PIB
El archivo porcentaje_inversion_pib_4T.csv tiene los porcentajes de inversión pública y privada con respecto al PIB (datos INEGI). Replique la gráfica original usando la plantilla INEGI como fondo.
7.1 Construcción de la gráfica
Código
inversion <- read_csv("https://raw.githubusercontent.com/JuveCampos/TC2001B.601-Ciencia-de-datos-ene-jun-2026/refs/heads/main/05_EXAMENES/preparacion_examen_practico/porcentaje_inversion_pib_4T.csv")
# Pasamos a formato largo (tidy) para poder graficar con ggplot
inversion_long <- inversion %>%
select(anio, `% Privada`, `% Pública`) %>%
pivot_longer(
cols = c(`% Pública`, `% Privada`),
names_to = "tipo",
values_to = "porcentaje"
) %>%
mutate(
tipo = factor(
tipo,
levels = c("% Privada", "% Pública"),
labels = c("% Privada", "% Pública")
)
)
# Replicamos la gráfica con los colores de MCV
grafica_inversion <- inversion_long %>%
ggplot(aes(x = anio, y = porcentaje, fill = tipo)) +
geom_col() +
geom_text(aes(label = str_c(porcentaje, "%")),
color = "white", angle = 90,
hjust = 1.1,
position = position_stack(),
family = "Ubuntu") +
scale_fill_manual(values = c(
"% Privada" = "#d75b99",
"% Pública" = "#6552d4"
)) +
scale_x_continuous(breaks = 1993:2025) +
scale_y_continuous(breaks = seq(0, 30, 5),
expand = expansion(c(0, 0.1)),
labels = scales::comma_format(suffix = "%")) +
labs(
title = "Inversión como % del PIB",
subtitle = "Como proporción del PIB - 4º trimestre de cada año",
x = NULL,
y = "Inversión como % del PIB",
fill = NULL,
caption = NULL
) +
theme_minimal() +
theme(
legend.position = "bottom",
plot.title = element_text(face = "bold", color = "#6552d4", size = 20),
plot.subtitle = element_text(color = "gray50", size = 16),
legend.text = element_text(color = "gray50"),
text = element_text(family = "Ubuntu"),
axis.text.x = element_text(angle = 90, hjust = 1, vjust = 0.5),
panel.grid.minor = element_blank(),
plot.margin = margin(t = 0.4, r = 0.4, b = 1.2, l = 0.4, unit = "cm"),
panel.grid.major = element_blank()
)
grafica_inversion7.2 Gráfica sobre la plantilla INEGI
A continuación mostramos la versión final de la gráfica con la plantilla PDF de INEGI como fondo, usando ggpubr::ggbackground():
Código
# Guardamos con plantilla en la carpeta
plt_impresion <- ggbackground(
gg = grafica_inversion,
background = "../preparacion_examen_practico/01_inegi.pdf"
)
ggsave(filename = "grafica_inversion.png",
plot = plt_impresion, device = "png",
height = 6, width = 12)8 Ejercicio 7 — Rutas de entrega (Cuarteto de Anscombe)
Una empresa de logística tiene 4 rutas de entrega. Para cada ruta se registraron 11 observaciones con km y tiempo. Datos: rutas_entrega.csv.
- Calcula por ruta: media y desviación estándar de
kmytiempo, y la correlación entre ambas. ¿Qué observas? - Gráfico de dispersión
kmvstiempopor ruta (facet_wrap) con línea de regresión en cada panel. - Párrafo sobre la importancia de la visualización.
8.1 (a) Estadísticas descriptivas por ruta
Código
rutas <- read_csv("https://raw.githubusercontent.com/JuveCampos/TC2001B.601-Ciencia-de-datos-ene-jun-2026/refs/heads/main/05_EXAMENES/nuevos_ejercicios_propuestos/rutas_entrega.csv")
tabla_rutas <- rutas %>%
group_by(ruta) %>%
summarise(
media_km = mean(km),
media_tiempo = mean(tiempo),
sd_km = sd(km),
sd_tiempo = sd(tiempo),
correlacion = cor(km, tiempo)
)
tabla_rutas %>% kable(digits = 3)| ruta | media_km | media_tiempo | sd_km | sd_tiempo | correlacion |
|---|---|---|---|---|---|
| Ruta_A | 9 | 7.501 | 3.317 | 2.032 | 0.816 |
| Ruta_B | 9 | 7.501 | 3.317 | 2.032 | 0.816 |
| Ruta_C | 9 | 7.500 | 3.317 | 2.030 | 0.816 |
| Ruta_D | 9 | 7.501 | 3.317 | 2.031 | 0.817 |
Observación. ¡Las medias, desviaciones estándar y correlaciones son prácticamente idénticas entre las 4 rutas! Este dataset corresponde al cuarteto de Anscombe (Anscombe, 1973): cuatro conjuntos de datos con estadísticas descriptivas casi iguales pero estructuras muy distintas. Lección: las estadísticas descriptivas nunca sustituyen a la visualización.
8.2 (b) Gráfico de dispersión por ruta
Código
grafica_rutas <- rutas %>%
ggplot(aes(x = km, y = tiempo)) +
geom_point(color = "#1e4c7d", size = 2) +
geom_smooth(method = "lm", se = FALSE, color = "#C8102E") +
facet_wrap(~ ruta) +
labs(
title = "Relación entre kilómetros recorridos y tiempo de entrega",
subtitle = "4 rutas de una empresa de logística (11 observaciones c/u)",
x = "Kilómetros",
y = "Tiempo (minutos)",
caption = "Fuente: Registros internos de la empresa"
) +
theme_minimal()
grafica_rutas8.3 (c) Importancia de la visualización
La visualización es crucial porque, aun cuando las cuatro rutas presentan estadísticas descriptivas (media, desviación estándar y correlación) prácticamente idénticas, la gráfica de dispersión revela que cada una tiene un patrón muy diferente: una muestra una relación lineal limpia, otra una curvatura, otra una línea con un outlier y otra un caso donde un solo punto extremo conduce toda la correlación. Si nos quedamos solo con los números, tomaríamos decisiones erróneas —por ejemplo, asumir que todas las rutas se comportan igual—. La gráfica nos permite ver la estructura real de los datos, detectar outliers y validar supuestos antes de ajustar modelos de regresión.
9 Ejercicio 8 — Dataset de salud
Dataset de 200 pacientes (salud.csv) con: edad, peso_kg, altura_cm, presion_sistolica, colesterol, horas_ejercicio_sem, glucosa.
- IDs con altura outlier (método IQR).
- Promedio de
presion_sistolica,colesterol,horas_ejercicio_semyglucosapor grupo de edad: jóvenes (≤29), adultos (30-60), mayores (61+). - Gráfica de barras para cada variable, con el orden jóvenes → adultos → mayores.
- Dispersión
presion_sistolicavsedad+ correlación e interpretación.
9.1 (1) Outliers de altura
Código
salud <- read_csv("https://raw.githubusercontent.com/JuveCampos/TC2001B.601-Ciencia-de-datos-ene-jun-2026/refs/heads/main/05_EXAMENES/nuevos_ejercicios_propuestos/salud.csv")
q1_alt <- quantile(salud$altura_cm, 0.25, na.rm = TRUE)
q3_alt <- quantile(salud$altura_cm, 0.75, na.rm = TRUE)
iqr_alt <- q3_alt - q1_alt
lim_inf_alt <- q1_alt - 1.5 * iqr_alt
lim_sup_alt <- q3_alt + 1.5 * iqr_alt
outliers_altura <- salud %>%
filter(altura_cm < lim_inf_alt | altura_cm > lim_sup_alt) %>%
select(paciente_id, altura_cm)
print(paste0("Q1=", q1_alt, " | Q3=", q3_alt, " | IQR=", iqr_alt))[1] "Q1=158.375 | Q3=171.975 | IQR=13.6"
[1] "Límites de altura: [137.975, 192.375]"
| paciente_id | altura_cm |
|---|---|
| 25 | 197.3 |
| 147 | 134.8 |
Respuesta. Los IDs en la tabla
outliers_alturacorresponden a las personas cuya altura cae fuera del rango \([Q_1 - 1.5 \cdot IQR,\; Q_3 + 1.5 \cdot IQR]\).
9.2 (2) Promedios por grupo de edad
Código
salud_grupos <- salud %>%
mutate(
grupo_edad = case_when(
edad <= 29 ~ "Jóvenes (<=29)",
edad <= 60 ~ "Adultos (30-60)",
TRUE ~ "Mayores (61+)"
),
# Aseguramos el orden: jóvenes, adultos, mayores
grupo_edad = factor(
grupo_edad,
levels = c("Jóvenes (<=29)", "Adultos (30-60)", "Mayores (61+)")
)
)
promedios_grupo <- salud_grupos %>%
group_by(grupo_edad) %>%
summarise(
presion_sistolica = mean(presion_sistolica, na.rm = TRUE),
colesterol = mean(colesterol, na.rm = TRUE),
horas_ejercicio = mean(horas_ejercicio_sem, na.rm = TRUE),
glucosa = mean(glucosa, na.rm = TRUE)
)
promedios_grupo %>% kable(digits = 2)| grupo_edad | presion_sistolica | colesterol | horas_ejercicio | glucosa |
|---|---|---|---|---|
| Jóvenes (<=29) | 112.05 | 189.66 | 7.10 | 78.93 |
| Adultos (30-60) | 121.98 | 209.61 | 5.68 | 85.05 |
| Mayores (61+) | 134.44 | 220.78 | 4.05 | 95.57 |
9.3 (3) Gráficas de barras por variable (facetas)
Código
# Pasamos a formato largo para poder facetar
promedios_largo <- promedios_grupo %>%
pivot_longer(
cols = -grupo_edad,
names_to = "variable",
values_to = "promedio"
) %>%
mutate(
variable = recode(variable,
presion_sistolica = "Presión sistólica",
colesterol = "Colesterol",
horas_ejercicio = "Horas ejercicio/sem",
glucosa = "Glucosa"
)
)
promedios_largo %>%
ggplot(aes(x = grupo_edad, y = promedio, fill = grupo_edad)) +
geom_col() +
geom_text(aes(label = round(promedio, 1)),
vjust = -0.4, size = 3.5) +
facet_wrap(~ variable, scales = "free_y") +
scale_fill_manual(values = c("#4FC3F7", "#1e4c7d", "#C8102E"),
guide = "none") +
labs(
title = "Promedios de variables de salud por grupo de edad",
x = NULL,
y = "Promedio",
caption = "Fuente: Dataset salud.csv (200 pacientes)"
) +
theme_minimal() +
theme(axis.text.x = element_text(angle = 20, hjust = 1))9.4 (4) Presión sistólica vs edad
Código
[1] "Correlación presión sistólica ~ edad: 0.654"
Código
salud %>%
ggplot(aes(x = edad, y = presion_sistolica)) +
geom_point(color = "#1e4c7d", alpha = 0.6) +
geom_smooth(method = "lm", se = TRUE, color = "#C8102E") +
labs(
title = "Relación entre edad y presión sistólica",
subtitle = paste0("Correlación de Pearson r = ",
round(correlacion_pe, 3)),
x = "Edad (años)",
y = "Presión sistólica (mmHg)",
caption = "Fuente: Dataset salud.csv"
) +
theme_minimal()Interpretación. La correlación es positiva y relativamente alta, lo que tiene sentido clínicamente: la presión sistólica tiende a aumentar con la edad. La gráfica de dispersión confirma este patrón —nube de puntos claramente ascendente y recta de regresión con pendiente positiva—, consistente con la literatura biomédica: el endurecimiento arterial progresivo con la edad eleva la presión sistólica.
10 Sesión
Código
R version 4.4.3 (2025-02-28)
Platform: aarch64-apple-darwin20
Running under: macOS 26.3
Matrix products: default
BLAS: /Library/Frameworks/R.framework/Versions/4.4-arm64/Resources/lib/libRblas.0.dylib
LAPACK: /Library/Frameworks/R.framework/Versions/4.4-arm64/Resources/lib/libRlapack.dylib; LAPACK version 3.12.0
locale:
[1] en_US.UTF-8/en_US.UTF-8/en_US.UTF-8/C/en_US.UTF-8/en_US.UTF-8
time zone: America/Mexico_City
tzcode source: internal
attached base packages:
[1] stats graphics grDevices utils datasets methods base
other attached packages:
[1] knitr_1.50 ggpubr_0.6.0 plotly_4.12.0 scales_1.4.0
[5] lubridate_1.9.4 forcats_1.0.0 stringr_1.6.0 dplyr_1.1.4
[9] purrr_1.2.0 readr_2.1.5 tidyr_1.3.1 tibble_3.3.1
[13] ggplot2_4.0.2 tidyverse_2.0.0
loaded via a namespace (and not attached):
[1] gtable_0.3.6 xfun_0.52 htmlwidgets_1.6.4 rstatix_0.7.2
[5] lattice_0.22-6 tzdb_0.5.0 vctrs_0.6.5 tools_4.4.3
[9] crosstalk_1.2.1 generics_0.1.4 curl_7.0.0 parallel_4.4.3
[13] pkgconfig_2.0.3 Matrix_1.7-2 data.table_1.17.8 RColorBrewer_1.1-3
[17] S7_0.2.0 lifecycle_1.0.4 compiler_4.4.3 farver_2.1.2
[21] carData_3.0-5 htmltools_0.5.8.1 yaml_2.3.10 lazyeval_0.2.2
[25] Formula_1.2-5 pillar_1.11.1 car_3.1-3 crayon_1.5.3
[29] abind_1.4-8 nlme_3.1-167 tidyselect_1.2.1 digest_0.6.37
[33] stringi_1.8.7 splines_4.4.3 labeling_0.4.3 fastmap_1.2.0
[37] grid_4.4.3 cli_3.6.5 magrittr_2.0.4 broom_1.0.10
[41] withr_3.0.2 backports_1.5.0 bit64_4.6.0-1 timechange_0.3.0
[45] rmarkdown_2.29 httr_1.4.7 bit_4.6.0 ggsignif_0.6.4
[49] hms_1.1.3 evaluate_1.0.4 viridisLite_0.4.2 mgcv_1.9-1
[53] rlang_1.1.6 glue_1.8.0 rstudioapi_0.17.1 vroom_1.6.5
[57] jsonlite_2.0.0 R6_2.6.1