Mapas en R con Leaflet — Caso: Ecobici en Julio de 2019

José Luis
Jan 26 · 8 min read

Esta semana leímos noticias acerca del cierre de estaciones del sistema Ecobici en Buenos Aires. Más allá de la discusión sobre los motivos de fondo aprovecho para mostrar algunas cosas que estuve viendo en R, en particular la librería leaflet que sirve para hacer mapas con la información que tenemos.

El Gobierno de la Ciudad pone a disposición varios sets de datos. En particular para esto nos va a interesar el último de recorridos de bicis, el cual se puede descargar acá (elegir el que dice Recorridos Realizados 2019 y tener paciencia para los 800 megas de descarga).

Por cierto si quieren aprender R desde cero hay excelentes tutoriales y cursos, acá la idea es solamente mostrar un trabajo básico con datos pero si les interesa pueden empezar bajando los programas acá y acá.

Cada vez que se trabaja con datos hay que arrancar teniendo en cuenta que se quiere saber en base a la información disponible. En este caso va a ser algo simple: mostrar las estaciones de Ecobici en un mapa, calcular cuantos viajes entran y salen de cada estación durante el mes de Julio de 2019 (el último del cual se tienen datos) y en base a eso aplicarle colores y formas para ilustrar en el mapa. Además queremos ver si las estaciones que fueron removidas del sistema recientemente tenían algún patrón en particular durante ese mes.

Comenzamos importando el dataset. Con el R Studio abierto vamos a import dataset y seleccionamos from text (base).

En el cuadro que aparece le ponemos de nombre viajes19 (esto es un ejercicio, si van a hacer algo serio cuiden bien las convenciones de nombres que es clave para saber que es cada cosa), el resto como está, recuerden destildar strings as factors.

Una vez que hacen click en Import va a tardar un rato (depende de la computadora que tengan) y cuando esté listo lo van a poder ver en Environment. Es un archivo muy pesado así que si le hacen click para verlo capaz les lleve otro ratito hasta que el programa vuelva a responder.

Para este ejemplo vamos a usar tres librerías: tidyverse, ggplot2 (para los gráficos) y leaflet (para los mapas).

library(tidyverse)
library(ggplot2)
library(leaflet)

Empezamos definiendo un vector con la lista de estaciones eliminadas del sistema recientemente. Tener la lista en un vector nos ayuda a hacer más fácil las operaciones en vez de chequear punto por punto.

EstEliminadas <- c(211,394,301,399,252,288,302,327,325,326,363,307,265,250,374,266,251,425)

El formato de la base de origen tiene los datos en el formato ISO estándar tipo “2019 12 31 23:59:59”. Para extraer la fecha y hora hay diversos métodos pero para esto vamos a simplemente cortar esa cadena en diferentes lugares de acuerdo a la posición de cada valor (año, mes… hasta minutos). Como en este caso la base sólo tiene valores para 2019 y el único corte por tiempo que vamos a hacer es por mes el único valor que necesitamos ese, tanto para viajes de origen como de destino.

viajes19 <- viajes19 %>%
mutate(MesOrigen = as.numeric(substr(fecha_origen_recorrido, 6, 7)),
EstOrigen = as.numeric(id_estacion_origen),
MesDestino = as.numeric(substr(fecha_destino_recorrido, 6, 7)),
EstDestino = as.numeric(id_estacion_destino)
)

Para aliviar un poco el tamaño de la base me voy a quedar solamente con los viajes que se iniciaron en julio.

viajes19 <- viajes19 %>%
filter(MesOrigen == 7)

Al margen de los datos de los viajes me voy a crear aparte una lista de estaciones para tener como referencia. La base original tiene repetido en cada registro la misma información, la idea es separar que corresponde a cada uno para juntarlo más adelante. De paso marcamos cuales fueron eliminadas recientemente usando el vector que creamos antes. Es mucho más cómodo trabajar con 400 registros que con varios millones.

Estaciones <- viajes19 %>%
select(EstOrigen, lat_estacion_origen, long_estacion_origen, nombre_estacion_origen, direccion_estacion_origen) %>%
group_by(EstOrigen) %>%
distinct(EstOrigen, .keep_all = TRUE)
Estaciones <- Estaciones %>%
mutate(Eliminada = case_when(
is.element(EstOrigen, EstEliminadas) == TRUE ~ 1,
TRUE ~ 0
))
Estaciones <- na.omit(Estaciones)Estaciones <- Estaciones %>%
rename(
“Estacion”= EstOrigen,
“lat” = lat_estacion_origen,
“long” = long_estacion_origen,
)

Vamos a crear dos tablas auxiliares (esto se puede hacer sobre la misma tabla pero queda más comprensible así) con los datos de cuantas bicis entraron y salieron en este mes en cada estación. También se les cambia el nombre a las columnas para unirlas más adelante.

ResultadosOrigen<-viajes19 %>%
group_by(EstOrigen) %>%
summarize(TotalViajesOrigen = n())
ResultadosDestino<-viajes19 %>%
group_by(EstDestino) %>%
summarize(TotalViajesDestino = n())
ResultadosOrigen <- ResultadosOrigen %>%
rename(“Estacion”= EstOrigen)
ResultadosDestino <- ResultadosDestino %>%
rename(“Estacion”= EstDestino)

Con esto logramos dos tablas (ResultadosOrigen y ResultadosDestino) que tienen dos columnas: una “Estacion” con el número de la estación y otra de TotalViajesOrigen/Destino según corresponda con los viajes de cada una. Vamos ahora a unirlas por el número de estación en una tabla con tres columnas: Estación, viajes origen (viajes que salen de esta estación) y viajes destino (viajes que llegan a esta estación).

ResultadosTotal <- merge(x = ResultadosOrigen, y = ResultadosDestino, by = “Estacion”)

Vamos a calcular lo que buscamos: tanto el total de viajes (sumando los viajes de origen y de destino) así como la diferencia entre ambos (para saber que estaciones son más demandadas para retirar bicis que para dejarlas o viceversa). Además vamos a sacar las otras columnas que ya no usamos.

ResultadosTotal <- ResultadosTotal %>%
mutate(ViajesTotal = TotalViajesOrigen + TotalViajesDestino,
DifTotal = TotalViajesOrigen — TotalViajesDestino)
ResultadosTotal <- ResultadosTotal %>%
select(Estacion, ViajesTotal,DifTotal)

Recuerdan la tabla de estaciones que armé más arriba? Ahora es cuando la vamos a usar para dotar a cada estación de sus propias estadísticas. Unimos ambas tablas (la de resultados viajes y la de estaciones) así:

ResultadosJulio19 <- merge(x = Estaciones, y = ResultadosTotal, by=”Estacion”)

Vamos a hacer un primer gráfico con los viajes totales de cada estación. Para esto requerimos la librería ggplot2. La idea es mostrar sobre el eje X el número de estación y sobre el Y el número de viajes, cambiando el color de las eliminadas para ver si surge algún patrón de uso.

ggplot(ResultadosJulio19, aes(x=Estacion, y=ViajesTotal, color=factor(Eliminada))) + 
geom_point()

Vemos que las estaciones están dentro de todo en el mismo rango que las demás. De haber alguna diferencia significativa la podríamos ver con los puntos yéndose hacia abajo o arriba según corresponda.

Pero como verlo en un gráfico sin idea de la ubicación espacial requiere un ejercicio intenso de la imaginación vamos a aplicar el mapa. Usando la misma tabla que ya tiene los datos de ubicación de cada estación (latitud y longitud) podemos hacer uno para comenzar ubicando las estaciones.

leaflet(ResultadosJulio19) %>% addTiles() %>%
addCircleMarkers(
color = ~”green”,
radius = ~3,
stroke = FALSE, fillOpacity = 0.8
)

Debería verse así

Dentro de R Studio el mapa es perfectamente manejable como cualquier otro: se puede mover, hacer zoom etc. Acá en Medium son imágenes fijas. Por lo que quería mostrar acá los mapas fijos son suficientes (creo). La ventaja de la interactividad es por ejemplo que al tocar en cada estación puede mostrar el nombre o alguna información adicional.

Vamos a hacer una serie de mapas basados en la información que ya tenemos para ver algunas de las capacidades básicas de leaflet (tiene muchas). Empezamos con pedirle que nos muestre en el mapa en rojo las estaciones que se eliminaron recientemente. Aclaro que quizás no estén representadas todas las estaciones que se removieron dado que algunas se inaguraron después de esta fecha, cuando liberen el próximo dataset deberían estar.

leaflet(ResultadosJulio19) %>% addTiles() %>%
addCircleMarkers(
color = ~ifelse(Eliminada==0,”green”,”red”),
radius = ~3,
stroke = FALSE, fillOpacity = 0.8
)

Ahora vamos a pedir que nos muestre de acuerdo al tamaño de cada círculo los viajes que tuvo cada estación.

leaflet(ResultadosJulio19) %>% addTiles() %>%
addCircleMarkers(
color = ~”blue”,
radius = ~2+(ViajesTotal/1000),
stroke = FALSE, fillOpacity = 0.8
)

Por último vamos a hacer un mapa que nos muestre no sólo el tamaño en relación a los viajes totales si no el color respecto a si de esa estación llegaron más bicis de las que salieron o al revés.

leaflet(ResultadosJulio19) %>% addTiles() %>%
addCircleMarkers(
color = ~ifelse(DifTotal > 0, “blue”, “red”),
radius = ~2+(ViajesTotal/1000),
stroke = FALSE, fillOpacity = 0.8
)

En este mapa podemos ver que hay algunos patrones de uso. Voy a hacer zoom en el macrocentro (y un poco más) para ilustrar mejor:

Entonces tenemos que de las tres terminales ferroviarias Retiro y Constitución son las que más viajes originan y allí predominan los viajes de salida (o sea los viajes donde el usuario toma una bici en vez de dejarla). Si bien en Retiro hay dos estaciones una al lado de la otra, la segunda sí recibe más viajes de los que emite (puede verse el círculo rojo debajo). También las estaciones de la zona de Parque Centenario tienden a emitir viajes en vez de recibirlos.

Esto es sólo un ejercicio que hice uniendo cosas que fui aprendiendo y quería compartir, hay un montón de cosas que se pueden analizar (como si los patrones de viaje cambian los días hábiles vs los no hábiles, comparar con meses anteriores, etc) y mejorar en el código (se pueden hacer más prolijos los gráficos, incluso capaz algo que no haya quedado bien por eso comparto todo esto). Cualquier comentario es más que bienvenido.

Cualquier cosa mi mail es jose011.18@gmail.com

Si llegaron hasta acá gracias por leer!

José Luis

Written by

ahora si sociólogo y en una relación complicada con sistemas

More From Medium

Also tagged Mobility

Related reads

Welcome to a place where words matter. On Medium, smart voices and original ideas take center stage - with no ads in sight. Watch
Follow all the topics you care about, and we’ll deliver the best stories for you to your homepage and inbox. Explore
Get unlimited access to the best stories on Medium — and support writers while you’re at it. Just $5/month. Upgrade