Código
rm(list=ls())
# Librerías necesarias
require(tidyverse)
require(ggfortify)
require(plotly)
require(kableExtra)
require(knitr)
require(devtools)
options(scipen=999)
Presentamos un ejemplo de modelos de regresión a partir de datos reales de temperatura y uso del sistema de bicicletas Ecobici de la Ciudad Autónoma de Buenos Aires.
A continuación, se muestran algunos posibles ajustes de regresión que vinculan la cantidad de usuarios del sistema Ecobici por día en función de la temperatura, distinguiendo por usos en días de semana o fin de semana.
rm(list=ls())
# Librerías necesarias
require(tidyverse)
require(ggfortify)
require(plotly)
require(kableExtra)
require(knitr)
require(devtools)
options(scipen=999)
En el dataset tempbici
de la librería datosIC
se incluyen datos de viajes con duración entre 5 y 60 minutos, cualquier día de la semana, desde el 4 de junio de 2022 hasta el 1ro de mayo de 2023. A continuación se muestran 10 datos de dicho conjunto.
::install_github("daniellaparada/datosIC")
devtoolslibrary(datosIC)
<- tempbici datos
fecha | n | tmin | tmax | tmed | dia | tipo_dia |
---|---|---|---|---|---|---|
2022-06-04 | 2495 | 9.2 | 15.1 | 12.15 | sábado | Fin de semana |
2022-06-05 | 1925 | 9.1 | 14.8 | 11.95 | domingo | Fin de semana |
2022-06-06 | 8308 | 8.8 | 13.5 | 11.15 | lunes | Lunes a viernes |
2022-06-07 | 8137 | 7.3 | 11.5 | 9.40 | martes | Lunes a viernes |
2022-06-08 | 8854 | 7.3 | 11.6 | 9.45 | miércoles | Lunes a viernes |
2022-06-09 | 8803 | 8.3 | 16.1 | 12.20 | jueves | Lunes a viernes |
2022-06-10 | 6890 | 4.2 | 11.5 | 7.85 | viernes | Lunes a viernes |
2022-06-11 | 2305 | 4.6 | 15.7 | 10.15 | sábado | Fin de semana |
2022-06-12 | 2561 | 6.4 | 14.6 | 10.50 | domingo | Fin de semana |
2022-06-13 | 9120 | 7.4 | 16.2 | 11.80 | lunes | Lunes a viernes |
Como puede verse en el siguiente gráfico, la cantidad de registros de viajes de esa duración varía en función de la temperatura máxima del día, y de si se trata de un día de la semana (lunes a viernes) o fin de semana (sábado y domingo).
ggplotly(
ggplot(data = filter(datos), aes(
x = tmax,
y = n,
key = fecha,
col = tipo_dia
+
)) labs(x = "Temperatura máxima", y = "Cantidad de usos de Ecobici") +
geom_point() +
scale_color_manual(values = c("Fin de semana" = "deeppink2", "Lunes a viernes" = "dodgerblue2")) +
theme_classic(),
source = "select",
tooltip = c("key")
)
En el gráfico se observa una tendencia similar en cuanto a cómo varía la cantidad de usos diarios del sistema en función de la temperatura máxima del día. Sin embargo, y aunque la tendencia es similar, la cantidad de usos se reduce notablemente los fines de semana.
El sistema de Ecobici es un sistema público de transporte y, como tal, es razonable que su uso sea intensivo durante los días hábiles, lo que explica las tendencias separadas que se ven en los gráficos anteriores. Sin embargo, en el conjunto de datos no se tiene información de feriados, por lo que hay algunas observaciones del grupo verde (lunes a viernes) que se observan próximos a los del grupo rojo (fines de semana). El 1ro de mayo es una de ellas. También hay fines de semana que coinciden con feriados en los que típicamente hay menos movimiento, como ocurre con la observación roja que corresponde al 1ro de enero. Y también ocurre lo contrario: fines de semana de uso atípico, como el de aquel domingo 18 de diciembre de 2022 en que Argentina se coronó campeón Mundial, y cuya observación, aunque de color rojo (domingo), se ubica dentro de la nube de puntos verdes.
Este dataset no cuenta con datos de precipitaciones para las fechas observadas, lo que podría ayudar a explicar las mermas en el uso del sistema de Ecobici de ciertas fechas [para más información sobre esto, puede consultarse la Sección 3]. Sin embargo, es notable ver que existe cierta tendencia entre la intensidad del uso y la temperatura. Y tal tendencia no obedece únicamente a una cuestión de temporadas climáticas (estaciones del año, por ejemplo). Esto puede observarse en los siguientes gráficos, en donde se muestra que la evolución de la temperatura en función de la fecha del año no exhibe el mismo comportamiento que el uso del sistema Ecobici.
ggplotly(
ggplot(data = filter(datos), aes(
x = fecha,
y = n,
key = tmax,
col = tipo_dia
+
)) labs(x = "Fecha", y = "Cantidad de usos de Ecobici") +
geom_point() +
scale_color_manual(values = c("Fin de semana" = "deeppink2", "Lunes a viernes" = "dodgerblue2")) +
theme_classic(),
source = "select",
tooltip = c("key")
)
ggplotly(
ggplot(data = filter(datos), aes(x = fecha, y = tmax, key=fecha)) +
labs(x = "Fecha", y = "Temperatura máxima") +
geom_point(colour = "deeppink4") +
theme_classic(),
source = "select",
tooltip = c("key")
)
Esto sugiere que un ajuste lineal podría no ser el más adecuado para modelar la relación entre estas variables. En la siguiente sección, se prueban ajustes lineales y cuadráticos para explicar el uso del sistema Ecobici en función de la temperatura máxima diaria, tanto para días de semana como para fines de semana.
El ajuste lineal sobre el dataset completo muestra lo que anticipaban los gráficos anteriores. Aun cuando se ajusta por tipo de día, no se capta por completo la relación que se observa entre las variables a partir de los datos.
ggplotly(
ggplot(data = filter(datos), aes(
x = tmax,
y = n,
color = tipo_dia,
key = fecha
+
)) labs(x = "Temperatura máxima", y = "Cantidad de usos de Ecobici") +
geom_point() +
scale_color_manual(values = c("Fin de semana" = "deeppink2", "Lunes a viernes" = "dodgerblue2")) +
geom_smooth(method = "lm") +
theme_classic(),
source = "select",
tooltip = c("key")
)
Los gráficos de diagnóstico exhiben estructura en los residuos en ambos ajustes.
autoplot(lm(n ~ tmax,
data = datos[datos$tipo_dia == "Lunes a viernes",]),
label.size = 3)
Las observaciones 121, 135 y 236 corresponden a los siguientes casos (todos feriados nacionales).
fecha | n | tmin | tmax | tmed | dia | tipo_dia |
---|---|---|---|---|---|---|
2022-11-21 | 2422 | 14.7 | 19.6 | 17.15 | lunes | Lunes a viernes |
2022-12-09 | 3500 | 22.4 | 34.6 | 28.50 | viernes | Lunes a viernes |
2023-05-01 | 18 | 11.1 | 19.5 | 15.30 | lunes | Lunes a viernes |
autoplot(lm(n ~ tmax,
data = datos[datos$tipo_dia == "Fin de semana", ]),
label.size = 3)
Las observaciones 13, 42, 58 y 62 corresponden a los siguientes casos.
fecha | n | tmin | tmax | tmed | dia | tipo_dia |
---|---|---|---|---|---|---|
2022-07-16 | 1403 | 8.4 | 11.7 | 10.05 | sábado | Fin de semana |
2022-10-23 | 5392 | 10.8 | 18.8 | 14.80 | domingo | Fin de semana |
2022-12-18 | 7660 | 19.5 | 27.2 | 23.35 | domingo | Fin de semana |
2023-01-01 | 12 | 19.5 | 26.6 | 23.05 | domingo | Fin de semana |
El ajuste cuadrático mejora el ajuste anterior y parece modelar mejor la estructura observada.
ggplotly(
ggplot(data = filter(datos), aes(
x = tmax,
y = n,
color = tipo_dia,
key = fecha
+
)) labs(x = "Temperatura máxima", y = "Cantidad de usos de Ecobici") +
geom_point() +
scale_color_manual(values = c("Fin de semana" = "deeppink2", "Lunes a viernes" = "dodgerblue2")) +
geom_smooth(method = "lm",
formula = y ~ poly(x, 2)) +
theme_classic(),
source = "select",
tooltip = c("key")
)
En efecto, los gráficos de diagnóstico confirman que parte de la estructura de los residuos fue resuelta.
autoplot(lm(n ~ poly(tmax, 2),
data = datos[datos$tipo_dia == "Lunes a viernes", ]),
label.size = 3)
Las observaciones 10, 121, 135, 220 y 236 corresponden a los siguientes casos (todos feriados nacionales).
fecha | n | tmin | tmax | tmed | dia | tipo_dia |
---|---|---|---|---|---|---|
2022-06-17 | 2397 | 5.8 | 13.2 | 9.50 | viernes | Lunes a viernes |
2022-11-21 | 2422 | 14.7 | 19.6 | 17.15 | lunes | Lunes a viernes |
2022-12-09 | 3500 | 22.4 | 34.6 | 28.50 | viernes | Lunes a viernes |
2023-04-07 | 3261 | 19.1 | 23.1 | 21.10 | viernes | Lunes a viernes |
2023-05-01 | 18 | 11.1 | 19.5 | 15.30 | lunes | Lunes a viernes |
autoplot(lm(n ~ poly(tmax, 2),
data = datos[datos$tipo_dia == "Fin de semana", ]),
label.size = 3)
Las observaciones 42, 58 y 62 corresponden a los siguientes casos.
fecha | n | tmin | tmax | tmed | dia | tipo_dia |
---|---|---|---|---|---|---|
2022-10-23 | 5392 | 10.8 | 18.8 | 14.80 | domingo | Fin de semana |
2022-12-18 | 7660 | 19.5 | 27.2 | 23.35 | domingo | Fin de semana |
2023-01-01 | 12 | 19.5 | 26.6 | 23.05 | domingo | Fin de semana |
El ajuste podría ser lineal para explicar el uso del sistema Ecobici para días templados, por ejemplo, con temperaturas máximas inferiores a los 25°C.
ggplotly(
ggplot(
data = filter(datos, tmax < 25),
aes(
x = tmax,
y = n,
color = tipo_dia,
key = fecha
)+
) labs(x = "Temperatura máxima (menor que 25°C)", y = "Cantidad de usos de Ecobici") +
geom_point() +
scale_color_manual(values = c("Fin de semana" = "deeppink2", "Lunes a viernes" = "dodgerblue2")) +
geom_smooth(method = "lm") +
theme_classic(),
source = "select",
tooltip = c("key")
)
Los gráficos de diagnóstico exhiben menos estructura en los residuos respecto del ajuste lineal que cuando se consideraban todas las posibles temperaturas máximas. Es decir, parece razonable suponer que la tendencia en el uso del sistema Ecobici es creciente en relación con la temperatura máxima, siempre que esta no exceda cierto límite.
autoplot(lm(n ~ tmax,
data = datos[(datos$tipo_dia == "Lunes a viernes" &
$tmax < 25), ]),
datoslabel.size = 3)
Las observaciones 10, 110, 122 y 135 corresponden a los siguientes casos (todos feriados nacionales).
fecha | n | tmin | tmax | tmed | dia | tipo_dia |
---|---|---|---|---|---|---|
2022-06-17 | 2397 | 5.8 | 13.2 | 9.50 | viernes | Lunes a viernes |
2022-11-21 | 2422 | 14.7 | 19.6 | 17.15 | lunes | Lunes a viernes |
2023-04-07 | 3261 | 19.1 | 23.1 | 21.10 | viernes | Lunes a viernes |
2023-05-01 | 18 | 11.1 | 19.5 | 15.30 | lunes | Lunes a viernes |
autoplot(lm(n ~ tmax,
data = datos[(datos$tipo_dia == "Fin de semana" &
$tmax < 25), ]),
datoslabel.size = 3)
Las observaciones 42, 46 y 48 corresponden a los siguientes casos.
fecha | n | tmin | tmax | tmed | dia | tipo_dia |
---|---|---|---|---|---|---|
2022-10-23 | 5392 | 10.8 | 18.8 | 14.80 | domingo | Fin de semana |
2022-12-24 | 2079 | 17.5 | 24.2 | 20.85 | sábado | Fin de semana |
2023-02-18 | 3614 | 9.4 | 23.7 | 16.55 | sábado | Fin de semana |
A continuación, se detallan aspectos de los conjuntos de datos que conformaron el dataset reducido para el desarrollo del ejemplo, a la vez que se incluyen las fuentes de los datos y el código utilizado para pre-procesarlo con la sintaxis de tidyverse
. De esta forma, puede fácilmente replicarse y/o adaptarse si así se lo desea.
El dataset reducido con el que se desarrolló el ejemplo y que surge de tal pre-procesamiento, es tempbici
de la librería datosIC
.
Los datos de este ejemplo corresponden a datos de temperatura de los últimos 365 días tomados del Servicio Meterológico Nacional (disponibles acá). En particular, se considerarán los datos procesados de temperatura mínimas y máximas registradas en Aeroparque desde el 4 de junio de 2022 al 3 de julio de 2023.
<-
temperatura read_table("./fuente/01_regresion/registro_temperatura365d_smn.txt") %>%
slice(2:n()) %>%
filter(NOMBRE == "AEROPARQUE") %>%
select(1:3) %>%
mutate(
fecha = dmy(FECHA),
tmin = as.double(TMIN),
tmax = as.double(TMAX),
tmed = 0.5 * (tmin + tmax)
)
Los datos de este ejemplo corresponden a datos de uso del sistema Ecobici de la Ciudad de Buenos Aires (disponibles acá). En particular, se considerarán los datos de los años 2022 y 2023 correspondientes a viajes de entre 5 minutos y 1 hora de duración.
Ecobici es el sistema de transporte público de bicicletas de la Ciudad de Buenos Aires, que tiene estaciones automáticas con bicicletas a disposición las 24 horas, todos los días del año. El sistema es gratuito para todas las personas residentes del país de lunes a viernes (días hábiles) con hasta cuatro viajes de 30 minutos cada uno. Sin embargo, si se utiliza por un tiempo mayor que el indicado o durante los fines de semana, existen diferentes pases con variados costos. A modo de referencia, el pase que habilita a hacer 6 viajes diarios de hasta 60 minutos cada uno cualquier día de la semana tiene un costo de $1.785 (junio 2023).
<- read_csv(
trips_2022 "./fuente/01_regresion/trips_2022.csv",
col_types = cols(fecha_origen_recorrido = col_datetime(format = "%Y-%m-%d %H:%M:%S"))
%>%
) mutate(fecha = format(as_date(ymd_hms(
fecha_destino_recorrido%>%
)))) filter(duracion_recorrido > 300 && duracion_recorrido < 3600) %>%
group_by(fecha) %>%
count() %>%
mutate(fecha = as_date(fecha))
<- read_csv(
trips_2023 "./fuente/01_regresion/trips_2023.csv",
col_types = cols(fecha_origen_recorrido = col_datetime(format = "%Y-%m-%d %H:%M:%S"))
%>%
) mutate(fecha = format(as_date(ymd_hms(
fecha_destino_recorrido%>%
)))) filter(duracion_recorrido > 300 && duracion_recorrido < 3600) %>%
group_by(fecha) %>%
count() %>%
mutate(fecha = as_date(fecha))
<- rbind(trips_2022, trips_2023) trips
tempbici
Para reducir los datos al estudio de interés, se crea un dataset conjunto, tempbici
, a partir de los datos de temperatura y de uso del sistema Ecobici en el que se dispone de las siguientes variables.
fecha
: fecha, en el formato año-mes-día.n
: cantidad de registros de uso del sistema EcoBici en la fecha indicada.tmin
: temperatura mínima registrada en esa fecha.tmax
: temperatura máxima registrada en esa fecha.tmed
: temperatura media, construida como el promedio entre la temperatura mínima y máxima de esa fecha.dia
: día de la semana de la fecha indicada.tipo_dia
: tipo de día (Fin de semana o Lunes a viernes) de la fecha indicada.<- trips %>%
trips filter(fecha >= min(temperatura$fecha) &
<= max(temperatura$fecha))
fecha
<-
datos left_join(trips, temperatura, by = c("fecha" = "fecha")) %>%
drop_na() %>%
mutate(
dia = weekdays(fecha),
tipo_dia = ifelse(dia %in% c("sábado", "domingo"), "Fin de semana", "Lunes a viernes")
%>%
) select(c(1, 2, 6:10))
El dataset tempbici
está disponible en la librería datosIC
.
library(datosIC)
tempbici
fecha | n | tmin | tmax | tmed | dia | tipo_dia |
---|---|---|---|---|---|---|
2022-06-04 | 2495 | 9.2 | 15.1 | 12.15 | sábado | Fin de semana |
2022-06-05 | 1925 | 9.1 | 14.8 | 11.95 | domingo | Fin de semana |
2022-06-06 | 8308 | 8.8 | 13.5 | 11.15 | lunes | Lunes a viernes |
2022-06-07 | 8137 | 7.3 | 11.5 | 9.40 | martes | Lunes a viernes |
2022-06-08 | 8854 | 7.3 | 11.6 | 9.45 | miércoles | Lunes a viernes |
2022-06-09 | 8803 | 8.3 | 16.1 | 12.20 | jueves | Lunes a viernes |
2022-06-10 | 6890 | 4.2 | 11.5 | 7.85 | viernes | Lunes a viernes |
2022-06-11 | 2305 | 4.6 | 15.7 | 10.15 | sábado | Fin de semana |
2022-06-12 | 2561 | 6.4 | 14.6 | 10.50 | domingo | Fin de semana |
2022-06-13 | 9120 | 7.4 | 16.2 | 11.80 | lunes | Lunes a viernes |
sessionInfo()
R version 4.2.3 (2023-03-15 ucrt)
Platform: x86_64-w64-mingw32/x64 (64-bit)
Running under: Windows 10 x64 (build 22621)
Matrix products: default
locale:
[1] LC_COLLATE=Spanish_Argentina.utf8 LC_CTYPE=Spanish_Argentina.utf8
[3] LC_MONETARY=Spanish_Argentina.utf8 LC_NUMERIC=C
[5] LC_TIME=Spanish_Argentina.utf8
attached base packages:
[1] stats graphics grDevices utils datasets methods base
other attached packages:
[1] datosIC_0.0.0.9000 devtools_2.4.5 usethis_2.1.6 knitr_1.42
[5] kableExtra_1.3.4 plotly_4.10.1 ggfortify_0.4.16 lubridate_1.9.2
[9] forcats_1.0.0 stringr_1.5.0 dplyr_1.1.2 purrr_1.0.1
[13] readr_2.1.4 tidyr_1.3.0 tibble_3.2.1 ggplot2_3.4.2
[17] tidyverse_2.0.0
loaded via a namespace (and not attached):
[1] nlme_3.1-162 fs_1.6.1 webshot_0.5.5 httr_1.4.5
[5] tools_4.2.3 profvis_0.3.7 utf8_1.2.3 R6_2.5.1
[9] lazyeval_0.2.2 mgcv_1.8-42 colorspace_2.1-0 urlchecker_1.0.1
[13] withr_2.5.0 tidyselect_1.2.0 gridExtra_2.3 prettyunits_1.1.1
[17] processx_3.8.0 curl_5.0.0 compiler_4.2.3 cli_3.6.1
[21] rvest_1.0.3 xml2_1.3.5 labeling_0.4.2 scales_1.2.1
[25] callr_3.7.3 systemfonts_1.0.4 digest_0.6.31 rmarkdown_2.21
[29] svglite_2.1.1 pkgconfig_2.0.3 htmltools_0.5.5 sessioninfo_1.2.2
[33] fastmap_1.1.1 highr_0.10 htmlwidgets_1.6.2 rlang_1.1.0
[37] rstudioapi_0.14 shiny_1.7.4 farver_2.1.1 generics_0.1.3
[41] jsonlite_1.8.4 crosstalk_1.2.0 magrittr_2.0.3 Matrix_1.5-4
[45] Rcpp_1.0.10 munsell_0.5.0 fansi_1.0.4 lifecycle_1.0.3
[49] stringi_1.7.12 yaml_2.3.7 pkgbuild_1.4.0 grid_4.2.3
[53] promises_1.2.0.1 crayon_1.5.2 miniUI_0.1.1.1 lattice_0.21-8
[57] splines_4.2.3 hms_1.1.3 ps_1.7.4 pillar_1.9.0
[61] pkgload_1.3.2 glue_1.6.2 evaluate_0.20 data.table_1.14.8
[65] remotes_2.4.2 vctrs_0.6.1 tzdb_0.3.0 httpuv_1.6.9
[69] gtable_0.3.4 cachem_1.0.7 xfun_0.39 mime_0.12
[73] xtable_1.8-4 later_1.3.0 viridisLite_0.4.2 memoise_2.0.1
[77] timechange_0.2.0 ellipsis_0.3.2
Servicio Meteorológico Nacional (info disponible acá y datos disponibles acá.)
Sistema Ecobici de la Ciudad Autónoma de Buenos Aires (info disponible acá y datos disponibles acá.)