Los campos de fechas suelen ser formatos difíciles de trabajar y procesar. ¿Cómo conocer la fecha mínima de un dataset? ¿Cómo calcular la diferencia entre dos fechas? Si bien existen funciones en Rbase para el manejo de fechas, el paquete lubridate cuenta con muchas funcionalidades para el manejo de fechas. Con este paquete, además de poder operar sobre las fechas, podemos también conocer los días de las semanas y los meses.
En primer lugar vamos a cargar las librerías. Recuerden instalarlas previamente con install.packages():
# install.packages("tidyverse")
library(tidyverse)
## ── Attaching packages ─────────────────────────────────────── tidyverse 1.3.1 ──
## ✔ ggplot2 3.3.5 ✔ purrr 0.3.4
## ✔ tibble 3.1.3 ✔ dplyr 1.0.9
## ✔ tidyr 1.1.3 ✔ stringr 1.4.0
## ✔ readr 2.1.2 ✔ forcats 0.5.1
## Warning: package 'readr' was built under R version 4.0.5
## ── Conflicts ────────────────────────────────────────── tidyverse_conflicts() ──
## ✖ dplyr::filter() masks stats::filter()
## ✖ dplyr::lag() masks stats::lag()
# install.packages("lubridate")
library(lubridate)
##
## Attaching package: 'lubridate'
## The following objects are masked from 'package:base':
##
## date, intersect, setdiff, union
Vamos a trabajar con datos de uso de bicicletas públicas entre
octubre 2021 y noviembre 2021. Los datos originales fueron obtenidos de
BADATA.
Sobre los datos originales, se realizó un geoproceso para obtener los
nombres del barrio y de la comuna donde se ubica la estación de origen y
la estación de llegada. También se realizó un ruteo a partir de datos de
OSM para calcular la distancia y la duración estimada.
El dataset puede descargarse desde Github.
bicicletas_raw <- read.csv("https://raw.githubusercontent.com/paulavidela/utdt_cienciadedatos/main/data/bicicletas-GCBA-oct-nov-2021.csv", header=TRUE, stringsAsFactors=TRUE, encoding = "UTF-8")
En primer lugar vamos a inspeccionar nuestra base de datos:
names(bicicletas_raw)
## [1] "periodo_recorrido" "fecha_origen_recorrido"
## [3] "nombre_estacion_origen" "barrio_estacion_origen"
## [5] "comuna_estacion_origen" "fecha_destino_recorrido"
## [7] "nombre_estacion_destino" "barrio_estacion_destino"
## [9] "comuna_estacion_destino" "modelo_bicicleta"
## [11] "duracion_calculada_min" "duracion_osrm_min"
## [13] "distancia_osrm_km"
Sobre las variables:
- periodo_recorrido: corresponde al año-mes del inicio del
recorrido
- fecha_origen_recorrido: corresponde a la fecha del origen del
recorrido
- nombre_estacion_origen: corresponde al nombre de la estación
de origen del recorrido
- barrio_estacion_origen: corresponde al barrio de la estación
de origen del recorrido
- comuna_estacion_origen: corresponde al comuna de la estación
de origen del recorrido
- fecha_destino_recorrido: corresponde a la fecha del destino
del recorrido
- nombre_estacion_destino: corresponde al nombre de la estación
de destino del recorrido
- barrio_estacion_destino: corresponde al barrio de la estación
de destino del recorrido
- comuna_estacion_destino: corresponde al comuna de la estación
de destino del recorrido
- modelo_bicicleta: corresponde al modelo de la bicicleta
elegida
- duracion_calculada_min: corresponde a la duración del
recorrido en minutos (según origen-destino)
- duracion_osrm_min: corresponde a la duración del recorrido
calculada por OSRM
- distancia_osrm_km: corresponde a la distancia recorrida según
OSRM
head(bicicletas_raw)
## periodo_recorrido fecha_origen_recorrido nombre_estacion_origen
## 1 2021-10 2021-10-09 16:03:42 UTC 002 - RETIRO I
## 2 2021-10 2021-10-09 14:53:58 UTC 002 - RETIRO I
## 3 2021-10 2021-10-09 10:30:22 UTC 002 - RETIRO I
## 4 2021-10 2021-10-09 15:00:35 UTC 002 - RETIRO I
## 5 2021-10 2021-10-09 17:47:07 UTC 002 - RETIRO I
## 6 2021-10 2021-10-09 15:09:20 UTC 002 - RETIRO I
## barrio_estacion_origen comuna_estacion_origen fecha_destino_recorrido
## 1 RETIRO 1 2021-10-09 16:42:33 UTC
## 2 RETIRO 1 2021-10-09 15:08:53 UTC
## 3 RETIRO 1 2021-10-09 11:06:05 UTC
## 4 RETIRO 1 2021-10-09 16:36:00 UTC
## 5 RETIRO 1 2021-10-09 18:00:17 UTC
## 6 RETIRO 1 2021-10-09 16:02:43 UTC
## nombre_estacion_destino barrio_estacion_destino comuna_estacion_destino
## 1 254 - PLAZA RAFAEL HERNANDEZ BELGRANO 13
## 2 032 - CATEDRAL SAN NICOLAS 1
## 3 292 - PLAZA BOLIVIA PALERMO 14
## 4 006 - PARQUE LEZAMA SAN TELMO 1
## 5 237 - MADERO OFFICE PUERTO MADERO 1
## 6 250 - FLENI BELGRANO 13
## modelo_bicicleta duracion_calculada_min duracion_osrm_min distancia_osrm_km
## 1 ICONIC 39 36.91 8.88
## 2 ICONIC 15 10.56 2.01
## 3 ICONIC 36 28.41 6.86
## 4 ICONIC 95 20.38 4.36
## 5 FIT 13 8.50 1.78
## 6 ICONIC 53 35.91 8.66
summary(bicicletas_raw)
## periodo_recorrido fecha_origen_recorrido
## 2021-10:246419 2021-11-26 15:55:38 UTC: 6
## 2021-11:265178 2021-10-04 14:11:18 UTC: 5
## 2021-10-05 18:22:00 UTC: 5
## 2021-10-06 15:38:16 UTC: 5
## 2021-10-15 20:24:22 UTC: 5
## 2021-10-20 20:25:52 UTC: 5
## (Other) :511566
## nombre_estacion_origen barrio_estacion_origen
## 014 - PACIFICO : 6894 PALERMO : 98039
## 009 - PARQUE LAS HERAS : 5512 RECOLETA : 53619
## 160 - GODOY CRUZ Y LIBERTADOR: 5401 BALVANERA : 33400
## 005 - PLAZA ITALIA : 5337 CABALLITO : 28047
## 096 - CARLOS GARDEL : 5333 SAN NICOLAS: 26794
## 147 - CONSTITUCIÓN : 5178 (Other) :269219
## (Other) :477942 NA's : 2479
## comuna_estacion_origen fecha_destino_recorrido
## Min. : 1.000 2021-11-17 19:42:12 UTC: 6
## 1st Qu.: 2.000 2021-11-26 18:57:54 UTC: 6
## Median : 6.000 2021-10-05 14:10:45 UTC: 5
## Mean : 7.459 2021-10-05 15:08:14 UTC: 5
## 3rd Qu.:14.000 2021-10-05 16:24:27 UTC: 5
## Max. :15.000 2021-10-25 20:31:01 UTC: 5
## NA's :2479 (Other) :511565
## nombre_estacion_destino barrio_estacion_destino
## 014 - PACIFICO : 6660 PALERMO : 97560
## 160 - GODOY CRUZ Y LIBERTADOR: 5548 RECOLETA : 53610
## 009 - PARQUE LAS HERAS : 5533 BALVANERA : 33526
## 096 - CARLOS GARDEL : 5415 CABALLITO : 27389
## 147 - CONSTITUCIÓN : 5262 SAN NICOLAS: 26506
## 005 - PLAZA ITALIA : 5089 (Other) :270507
## (Other) :478090 NA's : 2499
## comuna_estacion_destino modelo_bicicleta duracion_calculada_min
## Min. : 1.000 FIT :227668 Min. : 1.00
## 1st Qu.: 2.000 ICONIC:283929 1st Qu.: 10.00
## Median : 6.000 Median : 16.00
## Mean : 7.431 Mean : 20.45
## 3rd Qu.:14.000 3rd Qu.: 25.00
## Max. :15.000 Max. :7258.00
## NA's :2499
## duracion_osrm_min distancia_osrm_km
## Min. : 0.00 Min. : 0.000
## 1st Qu.: 7.17 1st Qu.: 1.500
## Median :11.18 Median : 2.360
## Mean :12.63 Mean : 2.737
## 3rd Qu.:16.71 3rd Qu.: 3.660
## Max. :74.71 Max. :17.280
##
str(bicicletas_raw)
## 'data.frame': 511597 obs. of 13 variables:
## $ periodo_recorrido : Factor w/ 2 levels "2021-10","2021-11": 1 1 1 1 1 1 1 1 1 1 ...
## $ fecha_origen_recorrido : Factor w/ 470709 levels "2021-09-30 19:58:09 UTC",..: 58804 58297 56942 58337 59615 58402 58398 59285 56654 57474 ...
## $ nombre_estacion_origen : Factor w/ 271 levels "001 - FACULTAD DE DERECHO",..: 2 2 2 2 2 2 2 2 2 2 ...
## $ barrio_estacion_origen : Factor w/ 47 levels "AGRONOMIA","ALMAGRO",..: 29 29 29 29 29 29 29 29 29 29 ...
## $ comuna_estacion_origen : int 1 1 1 1 1 1 1 1 1 1 ...
## $ fecha_destino_recorrido: Factor w/ 467136 levels "2021-10-01 00:00:10 UTC",..: 58335 57713 56540 58286 58919 58066 58073 58914 56232 56889 ...
## $ nombre_estacion_destino: Factor w/ 273 levels "001 - FACULTAD DE DERECHO",..: 192 28 217 6 181 189 189 194 96 2 ...
## $ barrio_estacion_destino: Factor w/ 47 levels "AGRONOMIA","ALMAGRO",..: 5 32 21 33 27 5 5 5 28 29 ...
## $ comuna_estacion_destino: int 13 1 14 1 1 13 13 13 2 1 ...
## $ modelo_bicicleta : Factor w/ 2 levels "FIT","ICONIC": 2 2 2 2 1 2 1 2 1 2 ...
## $ duracion_calculada_min : int 39 15 36 95 13 53 54 58 20 7 ...
## $ duracion_osrm_min : num 36.9 10.6 28.4 20.4 8.5 ...
## $ distancia_osrm_km : num 8.88 2.01 6.86 4.36 1.78 8.66 8.66 9.31 3.33 0 ...
Llama la atención la cantidad de niveles (levels) que tienen las fechas. Deberíamos convertir las fechas a formato fecha.
Observamos que hay dos variables relacionadas a la fecha:
- fecha_origen_recorrido: correspondiente a la fecha y hora
en la que se inició el recorrido en bicicleta
- fecha_destino_recorrido: correspondiente a la fecha y
hora en la que se finalizó el recorrido en bicicleta
Como podemos ver en el resultado de la función str(),
las dos variables son ‘factor’ es decir. Podemos confirmar la clase con
la función class()
class(bicicletas_raw$fecha_origen_recorrido)
## [1] "factor"
Como cargamos nuestros datos con el parámetros
stringsAsFactor = TRUE, R reconoció esa variable como de
tipo caracter y la convirtió a factor. Vamos a reconvertirla a caracter
para que pierda los niveles asociados a los factores.
bicicletas <- bicicletas_raw %>%
mutate(fecha_origen_recorrido = as.character(fecha_origen_recorrido),
fecha_destino_recorrido = as.character(fecha_destino_recorrido))
Veamos los resultados
str(bicicletas)
## 'data.frame': 511597 obs. of 13 variables:
## $ periodo_recorrido : Factor w/ 2 levels "2021-10","2021-11": 1 1 1 1 1 1 1 1 1 1 ...
## $ fecha_origen_recorrido : chr "2021-10-09 16:03:42 UTC" "2021-10-09 14:53:58 UTC" "2021-10-09 10:30:22 UTC" "2021-10-09 15:00:35 UTC" ...
## $ nombre_estacion_origen : Factor w/ 271 levels "001 - FACULTAD DE DERECHO",..: 2 2 2 2 2 2 2 2 2 2 ...
## $ barrio_estacion_origen : Factor w/ 47 levels "AGRONOMIA","ALMAGRO",..: 29 29 29 29 29 29 29 29 29 29 ...
## $ comuna_estacion_origen : int 1 1 1 1 1 1 1 1 1 1 ...
## $ fecha_destino_recorrido: chr "2021-10-09 16:42:33 UTC" "2021-10-09 15:08:53 UTC" "2021-10-09 11:06:05 UTC" "2021-10-09 16:36:00 UTC" ...
## $ nombre_estacion_destino: Factor w/ 273 levels "001 - FACULTAD DE DERECHO",..: 192 28 217 6 181 189 189 194 96 2 ...
## $ barrio_estacion_destino: Factor w/ 47 levels "AGRONOMIA","ALMAGRO",..: 5 32 21 33 27 5 5 5 28 29 ...
## $ comuna_estacion_destino: int 13 1 14 1 1 13 13 13 2 1 ...
## $ modelo_bicicleta : Factor w/ 2 levels "FIT","ICONIC": 2 2 2 2 1 2 1 2 1 2 ...
## $ duracion_calculada_min : int 39 15 36 95 13 53 54 58 20 7 ...
## $ duracion_osrm_min : num 36.9 10.6 28.4 20.4 8.5 ...
## $ distancia_osrm_km : num 8.88 2.01 6.86 4.36 1.78 8.66 8.66 9.31 3.33 0 ...
Lubridate tiene funciones que permiten calcular la fecha y hora
actual:
- today(): nos indica la fecha de hoy
- now(): nos indica la fecha y hora de ahora
today()
## [1] "2022-08-15"
¿Cuál es la clase de today()?
class(today())
## [1] "Date"
now()
## [1] "2022-08-15 16:04:19 -03"
¿Cuál es la clase de now()?
class(now())
## [1] "POSIXct" "POSIXt"
Existen tres tipos de formato de fechas:
- fecha (tipo ‘Date’)
- hora (tipo ‘Period’)
- fecha-hora (tipo ‘POSIXt’)
¿Cómo se transforman las variables?
Vamos a tomar los primeros 5 registros y vamos a transformar la
variable fecha_origen_recorrido. Para esto pueden utilizar
multiples funciones de lubridate dependiendo de como estén escritos los
campos. Vamos a mostrar algunas de ellas. Pueden ver otras maneras aqui.
registros10 <- bicicletas %>%
head(10) %>%
select(fecha_origen_recorrido) %>%
rename(original = fecha_origen_recorrido)
registros10
## original
## 1 2021-10-09 16:03:42 UTC
## 2 2021-10-09 14:53:58 UTC
## 3 2021-10-09 10:30:22 UTC
## 4 2021-10-09 15:00:35 UTC
## 5 2021-10-09 17:47:07 UTC
## 6 2021-10-09 15:09:20 UTC
## 7 2021-10-09 15:09:09 UTC
## 8 2021-10-09 17:01:17 UTC
## 9 2021-10-09 08:18:22 UTC
## 10 2021-10-09 12:28:06 UTC
Nuestro campo tiene fecha y hora. La fecha se encuentra en formato:
año(year), mes(month), día(day), hora(hour), minuto(minute), segundo
(second). Se utiliza entonces la función ymd_hms().
registros10 <- registros10 %>%
mutate(fecha_hora = ymd_hms(original))
registros10
## original fecha_hora
## 1 2021-10-09 16:03:42 UTC 2021-10-09 16:03:42
## 2 2021-10-09 14:53:58 UTC 2021-10-09 14:53:58
## 3 2021-10-09 10:30:22 UTC 2021-10-09 10:30:22
## 4 2021-10-09 15:00:35 UTC 2021-10-09 15:00:35
## 5 2021-10-09 17:47:07 UTC 2021-10-09 17:47:07
## 6 2021-10-09 15:09:20 UTC 2021-10-09 15:09:20
## 7 2021-10-09 15:09:09 UTC 2021-10-09 15:09:09
## 8 2021-10-09 17:01:17 UTC 2021-10-09 17:01:17
## 9 2021-10-09 08:18:22 UTC 2021-10-09 08:18:22
## 10 2021-10-09 12:28:06 UTC 2021-10-09 12:28:06
Veamos la clase de la nueva variable
class(registros10$fecha_hora)
## [1] "POSIXct" "POSIXt"
Podemos ver que la clase de la variable fecha_hora es de
POSIXct (fecha - hora) .
Como nuestra variable fecha_hora tiene una clase
adecuada, podemos ingresar a los componetes ‘año’, ‘mes’ y ‘día’ con las
funciones year(), month(),
day()
registros10 <- registros10 %>%
mutate(anio = year(fecha_hora),
mes = month(fecha_hora),
dia = day(fecha_hora))
registros10
## original fecha_hora anio mes dia
## 1 2021-10-09 16:03:42 UTC 2021-10-09 16:03:42 2021 10 9
## 2 2021-10-09 14:53:58 UTC 2021-10-09 14:53:58 2021 10 9
## 3 2021-10-09 10:30:22 UTC 2021-10-09 10:30:22 2021 10 9
## 4 2021-10-09 15:00:35 UTC 2021-10-09 15:00:35 2021 10 9
## 5 2021-10-09 17:47:07 UTC 2021-10-09 17:47:07 2021 10 9
## 6 2021-10-09 15:09:20 UTC 2021-10-09 15:09:20 2021 10 9
## 7 2021-10-09 15:09:09 UTC 2021-10-09 15:09:09 2021 10 9
## 8 2021-10-09 17:01:17 UTC 2021-10-09 17:01:17 2021 10 9
## 9 2021-10-09 08:18:22 UTC 2021-10-09 08:18:22 2021 10 9
## 10 2021-10-09 12:28:06 UTC 2021-10-09 12:28:06 2021 10 9
Vamos a generar una nueva variable de fecha, en formato día/mes/año.
registros10 <- registros10 %>%
mutate(solo_fecha= paste0(dia, "/", mes, "/", anio))
registros10
## original fecha_hora anio mes dia solo_fecha
## 1 2021-10-09 16:03:42 UTC 2021-10-09 16:03:42 2021 10 9 9/10/2021
## 2 2021-10-09 14:53:58 UTC 2021-10-09 14:53:58 2021 10 9 9/10/2021
## 3 2021-10-09 10:30:22 UTC 2021-10-09 10:30:22 2021 10 9 9/10/2021
## 4 2021-10-09 15:00:35 UTC 2021-10-09 15:00:35 2021 10 9 9/10/2021
## 5 2021-10-09 17:47:07 UTC 2021-10-09 17:47:07 2021 10 9 9/10/2021
## 6 2021-10-09 15:09:20 UTC 2021-10-09 15:09:20 2021 10 9 9/10/2021
## 7 2021-10-09 15:09:09 UTC 2021-10-09 15:09:09 2021 10 9 9/10/2021
## 8 2021-10-09 17:01:17 UTC 2021-10-09 17:01:17 2021 10 9 9/10/2021
## 9 2021-10-09 08:18:22 UTC 2021-10-09 08:18:22 2021 10 9 9/10/2021
## 10 2021-10-09 12:28:06 UTC 2021-10-09 12:28:06 2021 10 9 9/10/2021
El campo solo_fecha está en formato día(day),
mes(month), año(year). Se utiliza entonces la función
dmy().
registros10 <- registros10 %>%
mutate(fecha = dmy(solo_fecha))
registros10
## original fecha_hora anio mes dia solo_fecha
## 1 2021-10-09 16:03:42 UTC 2021-10-09 16:03:42 2021 10 9 9/10/2021
## 2 2021-10-09 14:53:58 UTC 2021-10-09 14:53:58 2021 10 9 9/10/2021
## 3 2021-10-09 10:30:22 UTC 2021-10-09 10:30:22 2021 10 9 9/10/2021
## 4 2021-10-09 15:00:35 UTC 2021-10-09 15:00:35 2021 10 9 9/10/2021
## 5 2021-10-09 17:47:07 UTC 2021-10-09 17:47:07 2021 10 9 9/10/2021
## 6 2021-10-09 15:09:20 UTC 2021-10-09 15:09:20 2021 10 9 9/10/2021
## 7 2021-10-09 15:09:09 UTC 2021-10-09 15:09:09 2021 10 9 9/10/2021
## 8 2021-10-09 17:01:17 UTC 2021-10-09 17:01:17 2021 10 9 9/10/2021
## 9 2021-10-09 08:18:22 UTC 2021-10-09 08:18:22 2021 10 9 9/10/2021
## 10 2021-10-09 12:28:06 UTC 2021-10-09 12:28:06 2021 10 9 9/10/2021
## fecha
## 1 2021-10-09
## 2 2021-10-09
## 3 2021-10-09
## 4 2021-10-09
## 5 2021-10-09
## 6 2021-10-09
## 7 2021-10-09
## 8 2021-10-09
## 9 2021-10-09
## 10 2021-10-09
Se observa que la variable fecha es de tipo ‘date’ y que
está en formato año-mes-día. Este es el formato por defecto para las
fechas en R.
Habiendo explorado algunas funciones iniciales en lubridate, ahora vamos
a analizar los patrones temporales en nuestro dataset.
Para preprocesar nuestro dataset, vamos a transformas las variables
fecha_origen_recorrido y
fecha_destino_recorrido a formato ‘fecha-hora’. Además
vamos a seleccionar nuestras variables de interés.
bicicletas_ok <- bicicletas %>%
mutate(fecha_hora_origen = ymd_hms(fecha_origen_recorrido),
fecha_hora_destino = ymd_hms(fecha_destino_recorrido)) %>%
select(nombre_estacion_origen, barrio_estacion_origen, fecha_hora_origen, nombre_estacion_destino, barrio_estacion_destino, fecha_hora_destino)
head(bicicletas_ok, 10)
## nombre_estacion_origen barrio_estacion_origen fecha_hora_origen
## 1 002 - RETIRO I RETIRO 2021-10-09 16:03:42
## 2 002 - RETIRO I RETIRO 2021-10-09 14:53:58
## 3 002 - RETIRO I RETIRO 2021-10-09 10:30:22
## 4 002 - RETIRO I RETIRO 2021-10-09 15:00:35
## 5 002 - RETIRO I RETIRO 2021-10-09 17:47:07
## 6 002 - RETIRO I RETIRO 2021-10-09 15:09:20
## 7 002 - RETIRO I RETIRO 2021-10-09 15:09:09
## 8 002 - RETIRO I RETIRO 2021-10-09 17:01:17
## 9 002 - RETIRO I RETIRO 2021-10-09 08:18:22
## 10 002 - RETIRO I RETIRO 2021-10-09 12:28:06
## nombre_estacion_destino barrio_estacion_destino fecha_hora_destino
## 1 254 - PLAZA RAFAEL HERNANDEZ BELGRANO 2021-10-09 16:42:33
## 2 032 - CATEDRAL SAN NICOLAS 2021-10-09 15:08:53
## 3 292 - PLAZA BOLIVIA PALERMO 2021-10-09 11:06:05
## 4 006 - PARQUE LEZAMA SAN TELMO 2021-10-09 16:36:00
## 5 237 - MADERO OFFICE PUERTO MADERO 2021-10-09 18:00:17
## 6 250 - FLENI BELGRANO 2021-10-09 16:02:43
## 7 250 - FLENI BELGRANO 2021-10-09 16:03:21
## 8 256 - PLAZA NORUEGA BELGRANO 2021-10-09 17:59:34
## 9 116 - HOSPITAL ALEMÁN RECOLETA 2021-10-09 08:38:52
## 10 002 - RETIRO I RETIRO 2021-10-09 12:35:20
En primer lugar, queremos calcular los viajes por día según fecha de
inicio. Con la función round_date() podemos redondear la
fecha.
viajes_diarios <- bicicletas_ok %>%
mutate(dia = round_date(fecha_hora_origen, "day")) %>%
group_by(dia) %>%
summarise(cantidad =n())
head(viajes_diarios, 10)
## # A tibble: 10 × 2
## dia cantidad
## <dttm> <int>
## 1 2021-10-01 00:00:00 3020
## 2 2021-10-02 00:00:00 8492
## 3 2021-10-03 00:00:00 1832
## 4 2021-10-04 00:00:00 5055
## 5 2021-10-05 00:00:00 10717
## 6 2021-10-06 00:00:00 11368
## 7 2021-10-07 00:00:00 10091
## 8 2021-10-08 00:00:00 7884
## 9 2021-10-09 00:00:00 3689
## 10 2021-10-10 00:00:00 4468
Veamos la variación en un gráfico
viajes_diarios %>%
ggplot() +
geom_line(aes(x=dia, y = cantidad), color = "darkslateblue") +
labs(title = "Viajes por día",
subtitle = "Buenos Aires Octubre - Noviembre 2021",
caption = "Fuente: BADATA",
x = "",
y = "") +
scale_y_continuous(breaks = seq(0, 15000, 2000)) +
theme_minimal()
Detectamos un patrón en el comportamiento: se observan picos de
descenso en el uso de bicicletas de manera frecuente.
Podríamos evaluar si este patrón varía según el barrio de origen y
destino. Para eso vamos a evaluar cuales son los 3 orígenes destino más
frecuentes.
od_frecuentes <- bicicletas_ok %>%
group_by(barrio_estacion_origen, barrio_estacion_destino ) %>%
summarise(cantidad =n()) %>%
arrange(desc(cantidad))
## `summarise()` has grouped output by 'barrio_estacion_origen'. You can override
## using the `.groups` argument.
head(od_frecuentes, 3)
## # A tibble: 3 × 3
## # Groups: barrio_estacion_origen [2]
## barrio_estacion_origen barrio_estacion_destino cantidad
## <fct> <fct> <int>
## 1 PALERMO PALERMO 47352
## 2 PALERMO RECOLETA 15524
## 3 RECOLETA PALERMO 14973
Vamos a filtrar esos viajes
bicicletas_filtro <- bicicletas_ok %>%
filter((barrio_estacion_origen == "PALERMO" & barrio_estacion_destino == "PALERMO" ) |
(barrio_estacion_origen == "PALERMO" & barrio_estacion_destino == "RECOLETA" ) |
(barrio_estacion_origen == "RECOLETA" & barrio_estacion_destino == "PALERMO" ))
Vamos a generar nuevamente el dataset diario
viajes_diarios_od <- bicicletas_filtro %>%
mutate(dia = round_date(fecha_hora_origen, "day"),
od = paste0(barrio_estacion_origen, " - ", barrio_estacion_destino)) %>%
group_by(dia, od) %>%
summarise(cantidad =n())
## `summarise()` has grouped output by 'dia'. You can override using the `.groups`
## argument.
viajes_diarios_od %>%
ggplot() +
geom_line(aes(x=dia, y = cantidad, color = od)) +
labs(title = "Viajes por día",
subtitle = "Buenos Aires Octubre - Noviembre 2021",
caption = "Fuente: BADATA",
x = "",
y = "",
color = "Origen-Destino") +
theme_minimal() +
theme(legend.position = "bottom")
Observamos un comportamiento muy similar para los viajes
Palermo-Recoleta y Recoleta-Palermo. ¿Se tratan de viajes de ida y
vuelta? Vamos a evaluar la segunda semana de noviembre. Podemos utilizar
la función week() para encontrar la semana.
week(ymd("2021-11-07"))
## [1] 45
recorridos_por_hora <- bicicletas_ok %>%
filter(((barrio_estacion_origen == "PALERMO" & barrio_estacion_destino == "RECOLETA" ) |
(barrio_estacion_origen == "RECOLETA" & barrio_estacion_destino == "PALERMO" )) &
week(fecha_hora_origen) == 45) %>%
mutate(dia_hora = round_date(fecha_hora_origen, "hour"),
od = paste0(barrio_estacion_origen, " - ", barrio_estacion_destino)) %>%
group_by(dia_hora, od) %>%
summarise(cantidad =n())
## `summarise()` has grouped output by 'dia_hora'. You can override using the
## `.groups` argument.
Veamos los resultados en un gráfico
recorridos_por_hora %>%
ggplot() +
geom_line(aes(x=dia_hora, y = cantidad, color = od)) +
labs(title = "Viajes por día hora",
subtitle = "Buenos Aires Octubre - Noviembre 2021",
caption = "Fuente: BADATA",
x = "",
y = "",
color = "Origen-Destino") +
theme_minimal()
Vemos que los picos no son contrarios, sino que ocurren ambos a la tarde.
¿Los recorridos estarán relacionados con los días de la semana? La
función wday() del paquete de lubridate permite calcular el
día de la semana.
wday(today())
## [1] 2
El día de la semana de formato numérico es poco claro. Podemos ajustar los parámetros label (para mostrar el día en texto) y abbr (texto completo o abreviado)
wday(today(), label = TRUE, abbr = FALSE)
## [1] Monday
## 7 Levels: Sunday < Monday < Tuesday < Wednesday < Thursday < ... < Saturday
Por defecto, los parámetros se encuentran de la siguiente manera:
label = FALSE y abbr =TRUE
Además, y en caso que sea necesario, es posible configurar el idioma con
el parámetro locale. Por ejemplo:
locale = "Spanish" para Windows o
locale = "es_ES.UTF-8" para IOS. También podemos ajustar el
parámetro week_start para determinar el inicio de la semana.
Por defecto, es week_start = 0 , es decir primero domingo.
Vamos a calcular el día de la semana en la que se iniciaron los
viajes. Además vamos a incoporar una variable para que evalúe si se
trata de un día laborable o si es fin de semana o feriado. Para crear
esta variable, vamos a usar la función case_when() para
definir de acuerdo a los casos. Nuestro dataset cuenta con los
siguientes feriados:
feriados <- c(ymd("2021-10-08"), ymd("2021-10-11"), ymd("2021-11-20"), ymd("2021-11-22"))
viajes_diarios <- viajes_diarios %>%
mutate(
dia = ymd(substr(dia,1,10)),
dia_sem = wday(dia, label = TRUE, abbr = FALSE, week_start = 1, locale = "es_ES.UTF-8"),
laborable = case_when(
dia %in% feriados ~ "No laborable",
dia_sem %in% c("sábado", "domingo") ~ "No laborable",
TRUE ~ "Laborable"
))
head(viajes_diarios, 10)
## # A tibble: 10 × 4
## dia cantidad dia_sem laborable
## <date> <int> <ord> <chr>
## 1 2021-10-01 3020 viernes Laborable
## 2 2021-10-02 8492 sábado No laborable
## 3 2021-10-03 1832 domingo No laborable
## 4 2021-10-04 5055 lunes Laborable
## 5 2021-10-05 10717 martes Laborable
## 6 2021-10-06 11368 miércoles Laborable
## 7 2021-10-07 10091 jueves Laborable
## 8 2021-10-08 7884 viernes No laborable
## 9 2021-10-09 3689 sábado No laborable
## 10 2021-10-10 4468 domingo No laborable
viajes_diarios %>%
ggplot() +
geom_col(aes(x=dia, y = cantidad, fill = laborable) )+
labs(title = "Viajes por día",
subtitle = "Buenos Aires Octubre - Noviembre 2021",
caption = "Fuente: BADATA",
x = "",
y = "",
fill = "Tipo de jornada") +
scale_y_continuous(breaks = seq(0, 15000, 2500)) +
scale_fill_brewer(palette = 7, type = "qual") +
theme_minimal() +
theme(legend.position = "bottom")
Se observa un menor uso de las bicicletas públicas en días no laborables. ¿Las bicicletas se utilizan como movilidad de última milla en viajes laborales? Veamos la cantidad de recorridos según horario de inicio del recorrido.
bicicletas_ok <- bicicletas_ok %>%
mutate(hora_inicio = hour(fecha_hora_origen),
dia = ymd(substr(fecha_hora_origen,1,10)),
dia_sem = wday(dia, label = TRUE, abbr = FALSE, week_start = 1, locale = "es_ES.UTF-8"),
laborable = case_when(
dia %in% feriados ~ "No laborable",
dia_sem %in% c("sábado", "domingo") ~ "No laborable",
TRUE ~ "Laborable"
))
bicicletas_ok %>%
ggplot() +
geom_bar(aes(x=hora_inicio)) +
labs(title = "Recorridos en bicicleta según hora de origen",
subtitle = "Buenos Aires Octubre - Noviembre 2021",
caption = "Fuente: BADATA",
fill = "",
x = "Hora",
y = "Cantidad (en miles)") +
scale_y_continuous(breaks =seq(0,100000, 10000), labels = seq(0, 100, 10)) +
scale_x_continuous(breaks = seq(0,23,2)) +
theme_minimal() +
facet_wrap(~laborable)
Finalmente, vamos a calcular la duración del recorrido, y evaluar si se modifica según día de la semana. Para eso, vamos a realizar una resta entre la hora de finalización y la hora de origen.
bicicletas_ok <- bicicletas_ok %>%
mutate(duracion_min = round(fecha_hora_destino - fecha_hora_origen, digits = 1))
¿Cómo se distribuye la duración de recorridos?
summary(as.numeric(bicicletas_ok$duracion_min))
## Min. 1st Qu. Median Mean 3rd Qu. Max.
## 1.00 10.20 16.40 20.45 25.50 7258.40
Hay algunos recorridos que superan las 10hs. Incluso el máximo llega a 7258.4 minutos. Para gráficar, se filtran los recorridos de más de 10hs (600 min)
bicicletas_ok %>%
filter(duracion_min <= 600) %>%
ggplot() +
geom_histogram(aes(x=duracion_min)) +
labs(title = "Distribución de la duración de los recorridos",
subtitle = "Buenos Aires Octubre - Noviembre 2021",
caption = "Fuente: BADATA",
fill = "",
x = "Hora",
y = "Cantidad (en miles)") +
scale_x_continuous(breaks =seq(0,600, 100)) +
scale_y_continuous(breaks = seq(0,600000,50000), labels = seq(0,600,50)) +
theme_minimal() +
facet_wrap(~laborable)
## `stat_bin()` using `bins = 30`. Pick better value with `binwidth`.
Vemos que la mayoría de los viajes tienen una duración de menos de 2hs (120min). ¿Varía según día de la semana?
bicicletas_ok %>%
filter(duracion_min <= 120) %>%
ggplot() +
geom_boxplot(aes(x = dia_sem,
y=duracion_min,
fill = as.character(dia_sem))) +
labs(title = "Duración de los recorridos",
y = "Duración (min)",
x = "Día de inicio") +
theme_minimal() +
scale_y_continuous(breaks = seq(0,130,20)) +
scale_fill_brewer(palette = 8, type = "qual") +
theme(legend.position = "none")
Podemos observar que el valor medio de los viajes es muy similar para los días de semana, y el comportamiento difiere levemente los fin de semana.
¡Con el paquete ‘lubridate’ podemos trabajar sencillamente con las variables de tipo fecha!