Este proyecto analiza los datos de viajes de todo el año 2024 del sistema público de bicicletas compartidas de Buenos Aires, Ecobici, para descubrir patrones de uso, picos de demanda y oportunidades para mejorar la movilidad urbana sostenible.
A medida que las ciudades en todo el mundo adoptan transportes más ecológicos, comprender el comportamiento en el uso de bicicletas compartidas es clave para optimizar la ubicación de estaciones, la gestión de la flota y la reducción de la congestión y las emisiones.
Utilizando el conjunto de datos más reciente y completo (~3,56 millones de viajes), este análisis ofrece información accionable para la planificación de ciudades inteligentes y estrategias de movilidad sostenible a nivel global.
Objetivos Clave:
Identificar las horas, días y patrones estacionales de mayor uso de bicicletas.
Mapear las estaciones y barrios más populares de origen y destino.
Explorar la duración de los viajes y la demografía de los usuarios (cuando esté disponible).
Proporcionar recomendaciones basadas en datos para mejorar el sistema.
Este informe reproducible demuestra habilidades en limpieza de datos, análisis exploratorio, visualización y narración de negocio utilizando R y Tableau.
Este análisis utiliza datos abiertos oficiales del Gobierno de la Ciudad de Buenos Aires.
ecobici_recorridos_realizados_2024.csvtrip_id: ID único del viajeduration_seconds: Duración del viaje (segundos)start_datetime / end_datetime: Hora de
inicio y finorigin_station_id / origin_station_name:
Estación de origenorigin_longitude / origin_latitude:
Coordenadas de origendestination_station_id /
destination_station_name: Estación de destinodestination_longitude /
destination_latitude: Coordenadas de destinouser_id, bike_model,
genderestaciones_ecobici_nuevo_sistema.csvNota de Calidad de Datos
Se intentó unir información de barrio, comuna y ubicación desde el
archivo de estaciones, pero falló (0% coincidencia). El análisis se basa
completamente en los nombres y coordenadas integrados en el archivo de
viajes. En futuras actualizaciones se podrán añadir insights a nivel de
barrio con un dataset de estaciones sincronizado.
Todos los datos son públicos y abiertos. Los datos de 2025 aún no están completamente disponibles a enero de 2026. Los nombres de columnas se han estandarizado al inglés para mayor claridad y legibilidad internacional.
Los datos brutos de viajes Ecobici (2024) se cargan silenciosamente. Los nombres originales de las columnas están en español, tal como fueron provistos por el portal de datos abiertos.
En esta etapa:
Después de la limpieza, muestro la estructura y las estadísticas básicas del dataset final.
trips_clean <- trips %>%
# Rename columns to English
rename(
trip_id = id_recorrido,
duration_seconds = duracion_recorrido,
start_datetime = fecha_origen_recorrido,
origin_station_id = id_estacion_origen,
origin_station_name = nombre_estacion_origen,
origin_station_address = direccion_estacion_origen,
origin_longitude = long_estacion_origen,
origin_latitude = lat_estacion_origen,
end_datetime = fecha_destino_recorrido,
destination_station_id = id_estacion_destino,
destination_station_name = nombre_estacion_destino,
destination_station_address = direccion_estacion_destino,
destination_longitude = long_estacion_destino,
destination_latitude = lat_estacion_destino,
user_id = id_usuario,
bike_model = modelo_bicicleta,
gender = genero
) %>%
# Clean and normalize station names
mutate(
# Remove initial numbers + spaces/dash
origin_station_name = str_trim(str_remove(origin_station_name, r"(^\d+\s*-?\s*)")),
origin_station_name = str_to_title(origin_station_name),
# Fix Roman numerals
origin_station_name = str_replace_all(origin_station_name, "\\bIi\\b", "II"),
origin_station_name = str_replace_all(origin_station_name, "\\bIii\\b", "III"),
origin_station_name = str_replace_all(origin_station_name, "\\bIv\\b", "IV"),
# Same for destination
destination_station_name = str_trim(str_remove(destination_station_name, r"(^\d+\s*-?\s*)")),
destination_station_name = str_to_title(destination_station_name),
destination_station_name = str_replace_all(destination_station_name, "\\bIi\\b", "II"),
destination_station_name = str_replace_all(destination_station_name, "\\bIii\\b", "III"),
destination_station_name = str_replace_all(destination_station_name, "\\bIv\\b", "IV")
) %>%
# Create new time-based features
mutate(
duration_minutes = duration_seconds / 60,
hour_start = hour(start_datetime),
weekday = wday(start_datetime, label = TRUE, abbr = TRUE, locale = "en_US.UTF-8"),
day_type = ifelse(weekday %in% c("Sat", "Sun"), "Weekend", "Weekday"),
month = month(start_datetime, label = TRUE, abbr = FALSE, locale = "en_US.UTF-8")
) %>%
# Filter invalid trips
filter(
duration_seconds >= 60 & duration_seconds <= 86400,
!is.na(start_datetime), !is.na(end_datetime),
!is.na(origin_station_id), !is.na(destination_station_id)
)
# Show glimpse
glimpse(trips_clean)## Rows: 3,234,209
## Columns: 22
## $ trip_id <dbl> 20428222, 20431744, 20424802, 20427241, 20…
## $ duration_seconds <dbl> 568, 1355, 680, 466, 1176, 1906, 695, 492,…
## $ start_datetime <dttm> 2024-01-23 18:36:00, 2024-01-23 22:41:20,…
## $ origin_station_id <dbl> 513, 460, 137, 99, 68, 17, 284, 432, 26, 5…
## $ origin_station_name <chr> "San Martin II", "Beiro Y Segurola", "Azop…
## $ origin_station_address <chr> "Av. San Martín 5129", "Segurola 3194", "A…
## $ origin_longitude <dbl> -58.49074, -58.51193, -58.36749, -58.43541…
## $ origin_latitude <dbl> -34.59713, -34.60750, -34.61560, -34.59610…
## $ end_datetime <dttm> 2024-01-23 18:45:28, 2024-01-23 23:03:55,…
## $ destination_station_id <dbl> 498, 382, 150, 206, 68, 186, 432, 284, 32,…
## $ destination_station_name <chr> "Habana", "Biarritz", "Rodrigo Bueno", "Fi…
## $ destination_station_address <chr> "Gral. José Gervasio Artigas 4298 (y Haban…
## $ destination_longitude <dbl> -58.49496, -58.47726, -58.35547, -58.43734…
## $ destination_latitude <dbl> -34.58660, -34.60543, -34.61875, -34.58495…
## $ user_id <dbl> 992557, 320782, 861425, 320714, 1041602, 9…
## $ bike_model <chr> "FIT", "FIT", "FIT", "FIT", "ICONIC", "FIT…
## $ gender <chr> "MALE", "FEMALE", "FEMALE", "OTHER", "MALE…
## $ duration_minutes <dbl> 9.466667, 22.583333, 11.333333, 7.766667, …
## $ hour_start <int> 18, 22, 15, 17, 21, 22, 19, 21, 17, 12, 11…
## $ weekday <ord> Tue, Tue, Tue, Tue, Tue, Tue, Tue, Tue, Tu…
## $ day_type <chr> "Weekday", "Weekday", "Weekday", "Weekday"…
## $ month <ord> January, January, January, January, Januar…
## Min. 1st Qu. Median Mean 3rd Qu. Max.
## 1.000 9.867 16.100 21.748 25.850 1439.133
Resultados Clave Después de la Limpieza
El dataset final contiene 3.234.209 viajes válidos (tras eliminar registros inválidos).
Las duraciones de los viajes en minutos tienen una mediana de ~16,1 minutos y un promedio de ~21,7 minutos, lo cual es típico en sistemas de bicicletas compartidas urbanas (trayectos cortos con algunos recorridos más largos).
La mayoría de los viajes están entre ~10 y 26 minutos (entre el primer y tercer cuartil).
Resumen de Reducción de Datos
| Etapa | Número de Viajes | % del Original |
|---|---|---|
| Original (crudo) | 3.559.284 | 100% |
| Después de limpieza | 3.234.209 | ~90,8% |
| Eliminados (inválidos) | ~325.075 | ~9,1% |
Este proceso de limpieza eliminó aproximadamente 325.000 registros inválidos o atípicos (~9% de los datos originales), lo cual es normal y esperado en datasets públicos a gran escala como este. Los datos restantes están limpios, consistentes y listos para un análisis más profundo.
Este gráfico de barras muestra los viajes iniciados por hora del día (0–23), destacando los patrones diarios de uso y las horas de mayor demanda.
trips_clean %>%
count(hour_start) %>%
ggplot(aes(x = factor(hour_start), y = n)) +
geom_bar(stat = "identity", fill = "steelblue", color = "white") +
labs(title = "Number of Trips by Hour of Day (2024)",
subtitle = "Clear morning and evening commute peaks",
x = "Hour of Day (0-23)",
y = "Number of Trips") +
scale_y_continuous(labels = comma) +
theme_minimal(base_size = 14) +
theme(
axis.text.x = element_text(angle = 0, vjust = 0.5),
axis.title.x = element_text(margin = margin(t = 25)),
axis.title.y = element_text(margin = margin(r = 25)),
plot.title = element_text(face = "bold", size = 16, margin = margin(b = 15)),
plot.subtitle = element_text(size = 12, margin = margin(b = 15)))Principales Conclusiones
El pico vespertino (16–18 hs) domina con 271.500–308.297 viajes por hora — fuerte patrón de regreso a casa.
Pico secundario en la mañana (7–9 hs): 117.583–147.119 viajes — desplazamiento de entrada al trabajo/estudio.
Mediodía (12–15 hs) estable en 172.710–220.351 viajes — mezcla de trámites y ocio.
Recomendaciones Potenciales
Aumentar la disponibilidad de bicicletas durante el pico vespertino (16–18 hs) para satisfacer la mayor demanda.
Explorar incentivos para la devolución de bicicletas en períodos de alta demanda.
Este gráfico de barras horizontal muestra las 10 estaciones de origen más utilizadas en 2024 (nombres normalizados), revelando los puntos de partida de mayor demanda.
trips_clean %>%
count(origin_station_name) %>%
top_n(10, n) %>%
mutate(origin_station_name = fct_reorder(origin_station_name, n)) %>%
ggplot(aes(x = n, y = origin_station_name)) +
geom_bar(stat = "identity", fill = "darkorange", color = "white") +
geom_text(aes(label = comma(n)), hjust = -0.1, size = 3.5, color = "black") +
labs(title = "Top 10 Origin Stations by Number of Trips (2024)",
subtitle = "Stations with highest departure demand",
x = "Number of trips",
y = "Origin Station Name") +
scale_x_continuous(labels = comma, expand = expansion(mult = c(0, 0.1))) +
theme_minimal(base_size = 14) +
theme(axis.text.y = element_text(size = 10),
axis.title.x = element_text(margin = margin(t = 25)),
axis.title.y = element_text(margin = margin(r = 25)),
plot.title = element_text(face = "bold", size = 16, margin = margin(b = 15)),
plot.subtitle = element_text(size = 12, margin = margin(b = 15))
)Conclusiones Clave
Estación principal: Constitución (35.051 viajes), seguida por Pacífico (34.119) y Plaza De La Shoá (32.473).
Las 10 estaciones principales representan aproximadamente el 8,9% de todos los viajes — mostrando una demanda concentrada en pocos puntos.
Muchas de las estaciones más utilizadas se alinean con nodos de transporte o áreas centrales, reforzando el enfoque en los desplazamientos diarios.
Recomendaciones Potenciales
Priorizar el suministro de bicicletas y el reequilibrio cerca de las principales estaciones de origen (ej. Constitución, Pacífico) durante las horas pico.
Considerar incentivos para la devolución de bicicletas en estos puntos de partida concurridos.
Nota sobre el Enfoque del Análisis
Este análisis prioriza las estaciones de origen como
el principal indicador de la demanda de salida (donde más se necesitan
bicicletas).
Las estaciones de destino reflejan patrones de llegada y pueden
explorarse en futuros análisis para estudiar flujos completos de viajes
o el movimiento neto de bicicletas.
Este gráfico de barras muestra el número promedio de viajes por día en días laborables frente a fines de semana (normalizado por días únicos para tener en cuenta que los días laborables son ~2,5× más numerosos).
trips_clean %>%
group_by(day_type) %>%
summarise(
total_trips = n(),
num_days = n_distinct(as.Date(start_datetime)),
avg_trips_per_day = total_trips/num_days
) %>%
ggplot(aes(x = day_type, y = avg_trips_per_day, fill = day_type)) +
geom_bar(stat = "identity", width = 0.6) +
geom_text(aes(label = comma(round(avg_trips_per_day))), vjust = -0.5, size = 5, color = "black") +
scale_fill_manual(values = c("Weekday" = "steelblue", "Weekend" = "darkorange")) +
labs(title = "Average trips per Day: Weekday vs Weekend (2024)",
subtitle = "Normalized by number of unique days in each category",
x = "",
y = "Average Trips per Day") +
scale_y_continuous(labels = comma) +
theme_minimal(base_size = 14) +
theme(legend.position = "none",
plot.title = element_text(face = "bold", size = 16, margin = margin(b = 15)),
plot.subtitle = element_text(size = 12, margin = margin(b = 15)),
axis.title.x = element_blank(),
axis.title.y = element_text(margin = margin(r = 25)),
)Conclusiones Clave
El promedio de días laborables es significativamente mayor que el de fines de semana, confirmando el desplazamiento diario como principal caso de uso.
El uso en fines de semana es menor pero igualmente considerable, lo que sugiere cierta actividad recreativa o de ocio los sábados y domingos.
La relación entre días laborables y fines de semana (~2,6:1 por día) refuerza el patrón de desplazamiento observado en el análisis de horas pico.
Recomendaciones Potenciales
Priorizar la disponibilidad de bicicletas y el reequilibrio en días laborables durante las horas pico.
Explorar promociones de fin de semana para impulsar el uso recreativo.
Estos mapas de calor interactivos visualizan la distribución geográfica de los orígenes (azul) y destinos (rojo) de los viajes en Buenos Aires (muestra 2024).
morning_origins <- trips_clean %>% filter(hour_start >= 6 & hour_start <= 11)
leaflet(morning_origins %>% sample_n(10000)) %>%
addProviderTiles("CartoDB.Positron") %>%
addHeatmap(
lng = ~origin_longitude,
lat = ~origin_latitude,
radius = 10,
blur = 20,
max = 0.05,
gradient = c("white", "lightblue", "blue", "darkblue")
) %>%
setView(lng = -58.45, lat = -34.60, zoom = 12) %>%
addControl(html = "<h4>Morning Origins (6–11 AM)</h4><p>Blue = high density</p>", position = "topright")evening_destinations <- trips_clean %>% filter(hour_start >= 15 & hour_start <= 20)
leaflet(evening_destinations %>% sample_n(10000)) %>%
addProviderTiles("CartoDB.Positron") %>%
addHeatmap(
lng = ~destination_longitude,
lat = ~destination_latitude,
radius = 10,
blur = 20,
max = 0.05,
gradient = c("white", "yellow", "orange", "red", "darkred")
) %>%
setView(lng = -58.45, lat = -34.60, zoom = 12) %>%
addControl(html = "<h4>Evening Destinations (15–20 hs)</h4><p>Red = high density</p>", position = "topright")Conclusiones Clave – Flujos de Desplazamiento: Orígenes Matutinos vs Destinos Vespertinos
Los orígenes matutinos (azul) muestran una alta concentración en áreas centrales y del norte (ej. Microcentro, Palermo, Recoleta), mientras que los destinos vespertinos (rojo) mantienen alta densidad en el centro pero con mayor dispersión por la ciudad.
Este patrón indica un flujo de desplazamiento en el que las personas inician viajes en zonas centrales/residenciales por la mañana y regresan a zonas residenciales más dispersas por la tarde.
La fuerte saturación central en ambos períodos sugiere que el núcleo de la ciudad actúa como un gran hub tanto de partidas como de llegadas.
Recomendaciones Potenciales
Priorizar la disponibilidad de bicicletas en clusters centrales de alta densidad durante las salidas matutinas y las llegadas vespertinas para satisfacer la demanda persistente en el centro.
Usar un reequilibrio dinámico para redistribuir el exceso de bicicletas desde el centro (donde se acumulan durante el día) hacia áreas residenciales más dispersas en la tarde, asegurando disponibilidad para los viajes de regreso.
Nota sobre la muestra
Se utilizó una muestra aleatoria de 10.000 viajes para mejorar el rendimiento interactivo; el análisis del dataset completo muestra patrones espaciales idénticos.
Este diagrama de caja muestra la distribución de las duraciones de los viajes en minutos según el tipo de día, revelando longitudes de uso típicas.
trips_clean %>%
ggplot(aes(x = day_type, y = duration_minutes, fill = day_type)) +
geom_boxplot(outlier.shape = NA) +
scale_fill_manual(values = c("Weekday" = "steelblue", "Weekend" = "darkorange")) +
labs(title = "Trip Duration Distribution by Day Type",
subtitle = "Boxplot of duration in minutes (outliers removed for clarity)",
x = "",
y = "Duration (minutes)",
caption = "Boxplot explanation: The box encloses the middle 50% of trips (from 25% to 75%).\nThe thick line inside is the median (50%). Whiskers show the typical range (excluding extreme outliers).") +
scale_y_continuous(limits = c(0, 60)) +
theme_minimal() +
theme(legend.position = "none",
axis.title.y = element_text(margin = margin(r = 25), size = 13),
axis.text.x = element_text(size = 12),
axis.text.y = element_text(size = 10),
plot.title = element_text(face = "bold", size = 15, margin = margin(b = 15)),
plot.subtitle = element_text(size = 12, margin = margin(b = 15)),
plot.caption = element_text(hjust = 0, size = 10, color = "gray50")) +
# Add labels
# Q1
stat_summary(fun = quantile, fun.args = list(probs = 0.25), geom = "text",
aes(label = "Q1 (25%)"), hjust = -0.4, vjust = 1.1, size = 3.5, color = "black") +
# Median
stat_summary(fun = median, geom = "text",
aes(label = "Median (50%)"), hjust = -0.1, vjust = -0.5, size = 4, color = "black", fontface = "bold") +
# Q3
stat_summary(fun = quantile, fun.args = list(probs = 0.75), geom = "text",
aes(label = "Q3 (75%)"), hjust = -0.4, vjust = -0.5, size = 3.5, color = "black")
Conclusiones Clave
Las duraciones de los viajes son generalmente cortas, con una mediana de ~16,1 minutos y un promedio de ~21,7 minutos — típico en sistemas de bicicletas compartidas urbanas (traslados rápidos o trámites).
Los viajes en días laborables tienden a ser ligeramente más cortos (más enfocados en el desplazamiento), mientras que los viajes de fin de semana muestran mayor variación (probablemente incluyendo ocio o recorridos recreativos más largos).
La mayoría de los viajes (75% o más) duran menos de ~26 minutos, lo que indica un uso eficiente y de corta distancia.
Recomendaciones Potenciales
Aprovechar el límite gratuito existente de 30 minutos en días laborables promoviendo viajes cortos y eficientes (ej. campañas que incentiven desplazamientos menores a 30 minutos para evitar cargos).
Explorar la extensión del tiempo gratuito o del número de viajes en fines de semana para impulsar el uso recreativo, ya que los viajes de fin de semana muestran más variación y potencial para recorridos de ocio más largos.
Este gráfico de barras muestra el porcentaje de viajes por género, proporcionando información demográfica.
trips_clean %>%
filter(!is.na(gender)) %>% # Remove NA
count(gender) %>%
mutate(pct = n / sum(n) * 100) %>%
ggplot(aes(x = gender, y = pct, fill = gender)) +
geom_bar(stat = "identity") +
geom_text(aes(label = paste0(round(pct, 1), "%")), vjust = -0.5, size = 4) +
scale_fill_manual(values = c("MALE" = "steelblue", "FEMALE" = "darkorange", "OTHER" = "gray")) +
labs(title = "Percentage of Trips by Gender (2024)",
x = "Gender",
y = "Percentage (%)") +
scale_y_continuous(labels = scales::percent_format(scale = 1)) +
theme_minimal() +
theme(legend.position = "none",
axis.title.y = element_text(margin = margin(r = 25), size = 13),
axis.title.x = element_text(margin = margin(t = 25), size = 13),
axis.text.x = element_text(size = 12),
axis.text.y = element_text(size = 10),
plot.title = element_text(face = "bold", size = 15, margin = margin(b = 15)),
plot.subtitle = element_text(size = 12, margin = margin(b = 15)))Conclusiones Clave – Uso por Género
Los usuarios masculinos representan la mayoría de los viajes (~60,8%), mientras que las usuarias femeninas constituyen ~31,6%.
Un pequeño porcentaje (~7,3%) se clasifica como “Otro”, con valores faltantes insignificantes (0,3%).
El desequilibrio de género sugiere oportunidades para aumentar la participación femenina mediante campañas específicas, mejoras de seguridad o marketing inclusivo.
Recomendaciones Potenciales
Lanzar iniciativas para impulsar el uso femenino (ej. eventos exclusivos para mujeres, características de seguridad o promociones dirigidas a trabajadoras/estudiantes).
Monitorear las tendencias de género a lo largo del tiempo para evaluar el impacto de los esfuerzos de inclusión.
Este gráfico de barras muestra el número total de viajes por mes en 2024, revelando patrones estacionales de uso.
trips_clean %>%
count(month) %>%
mutate(month = factor(month, levels = month.name)) %>% # Sort chronologically
ggplot(aes(x = month, y = n, fill = n)) +
geom_bar(stat = "identity") +
geom_text(aes(label = comma(n)), vjust = -0.5, size = 3.5, color = "black") +
scale_fill_gradient(low = "lightblue", high = "darkblue") +
labs(title = "Total Trips by Month (2024)",
subtitle = "Seasonal usage patterns throughout the year",
x = "Month",
y = "Number of Trips") +
scale_y_continuous(labels = comma) +
theme_minimal() +
theme(
axis.title.y = element_text(margin = margin(r = 25), size = 13),
axis.title.x = element_text(margin = margin(t = 25), size = 13),
axis.text.x = element_text(angle = 45, hjust = 1, size = 12),
axis.text.y = element_text(size = 10),
plot.title = element_text(face = "bold", size = 15, margin = margin(b = 15)),
plot.subtitle = element_text(size = 12, margin = margin(b = 15))
)Conclusiones Clave
El uso alcanza su pico en la primavera tardía y el inicio del verano (septiembre–diciembre), con los valores más altos en octubre (335.005 viajes) y noviembre (322.054 viajes).
El menor uso ocurre en invierno (junio–agosto), con el mínimo en julio (215.163 viajes), probablemente debido al clima más frío en Buenos Aires.
En general, existe un claro patrón estacional: mayor cantidad de viajes durante los meses cálidos (primavera tardía/verano temprano) y menor en invierno, típico de los sistemas de bicicletas compartidas al aire libre en el hemisferio sur.
Recomendaciones Potenciales
Aumentar la disponibilidad de bicicletas y los esfuerzos de marketing durante la temporada alta (septiembre–diciembre) para aprovechar la mayor demanda.
Considerar operaciones reducidas o incentivos específicos en los meses de invierno (junio–agosto) para mantener el compromiso durante los períodos de menor uso.
Este gráfico de barras horizontal muestra el flujo neto de bicicletas por estación (destinos menos orígenes, es decir, llegadas menos partidas) en 2024.
Los valores positivos (azul) indican exceso de bicicletas (más llegadas, es decir, destinos).
Los valores negativos (naranja) indican escasez de bicicletas (más partidas, es decir, orígenes).
Las estaciones están ordenadas desde el mayor flujo neto positivo (arriba) hasta el menor negativo (abajo).
# Count departures by station
departures <- trips_clean %>%
count(origin_station_name, name = "departures")
# Count arrivals by station
arrivals <- trips_clean %>%
count(destination_station_name, name = "arrivals")
# Join and calculate net_flow
net_flow <- departures %>%
full_join(arrivals, by = c("origin_station_name" = "destination_station_name")) %>%
mutate(
departures = coalesce(departures, 0),
arrivals = coalesce(arrivals, 0),
net_flow = arrivals - departures,
station_clean = fct_reorder(origin_station_name, net_flow, .desc = FALSE) # Sort desc by real net_flow
) %>%
filter(abs(net_flow) > 1000) %>%
top_n(20, abs(net_flow))
# Net flow bar
net_flow %>%
ggplot(aes(x = net_flow, y = station_clean, fill = net_flow > 0)) +
geom_bar(stat = "identity") +
geom_text(aes(label = comma(net_flow)), hjust = ifelse(net_flow > 0, -0.1, 1.1), size = 3.5) +
scale_fill_manual(values = c("TRUE" = "steelblue", "FALSE" = "darkorange")) +
labs(title = "Net Bike Flow by Station (Top 20 Extremes)",
subtitle = "Negative = excess departures (need addition), Positive = excess arrivals (need removal)",
x = "Net Flow (Arrivals - Departures)",
y = "Station Name") +
scale_x_continuous(labels = comma) +
theme_minimal() +
theme(legend.position = "none",
axis.title.y = element_text(margin = margin(r = 25), size = 16),
axis.title.x = element_text(margin = margin(t = 25), size = 16),
axis.text.x = element_text(size = 12),
axis.text.y = element_text(size = 10),
plot.title = element_text(face = "bold", size = 18, margin = margin(b = 15)),
plot.subtitle = element_text(size = 14, margin = margin(b = 15)))Conclusiones Clave
Estaciones como Juan Manuel De Blanes (+3.056) y Parque Lezama (+2.871) tienen el mayor flujo neto positivo (exceso de llegadas, es decir, destinos) — acumulan bicicletas y requieren retiro.
Estaciones como Cerrito (-2.064) y Aduana (-1.549) presentan el mayor flujo neto negativo (exceso de partidas, es decir, orígenes) — pierden bicicletas y necesitan reposición.
Los extremos principales destacan estaciones que requieren reequilibrio frecuente para mantener la disponibilidad.
Recomendaciones Potenciales
Priorizar el reequilibrio en estaciones con flujo neto positivo (retirar bicicletas en exceso).
Priorizar el reequilibrio en estaciones con flujo neto negativo (agregar bicicletas).
Usar modelos predictivos para anticipar el flujo neto diario según la hora del día y patrones históricos.
Para hacer el análisis más interactivo y exploratorio, se creó un panel en Tableau con el dataset limpio.
Aspectos Destacados del Panel
Enlace al panel interactivo completo
Ver el Dashboard Ecobici 2024 en Tableau Public
Captura de Pantalla
Este proyecto analizó más de 3,2 millones de viajes de Ecobici en 2024 para descubrir patrones clave de uso en el sistema público de bicicletas compartidas de Buenos Aires.
Principales Hallazgos
Fuerte enfoque en desplazamientos: pico vespertino (16–18 hs, hasta 308k viajes/hora) y pico secundario matutino (7–10 hs).
Promedio en días laborables ~10.724 viajes/día vs ~4.081 en fines de semana (relación ~2,6:1).
Principales estaciones de origen (Constitución 35k, Pacífico 34k) y mapas de calor espaciales muestran demanda concentrada en áreas centrales (Microcentro, Palermo, Recoleta).
Los orígenes matutinos se agrupan en zonas residenciales/centrales, los destinos vespertinos se dispersan, confirmando el flujo bidireccional de desplazamientos.
Duración de viajes: mediana ~16,1 min, promedio ~21,7 min — la mayoría menores a 30 min.
Distribución por género: Hombres ~60,8%, Mujeres ~31,6%.
Picos estacionales en primavera tardía/verano temprano (octubre 335k), mínimos en invierno (julio 215k).
Extremos de flujo neto (ej. Juan Manuel De Blanes +3.056, Cerrito -2.064) destacan necesidades de reequilibrio.
Lecciones Aprendidas
Las fuentes de datos abiertos pueden tener inconsistencias (ej. incompatibilidad de IDs de estaciones) — confiar en coordenadas integradas aseguró cobertura completa sin dependencias externas.
Las técnicas de normalización (como promedios por día) son críticas para evitar conclusiones engañosas al comparar grupos de tamaños desiguales.
El muestreo (10.000 viajes) logra un equilibrio práctico entre rendimiento interactivo y precisión analítica en visualizaciones a gran escala.
La terminología consistente (ej. orígenes/destinos en lugar de mezclar con partidas/llegadas) y las explicaciones claras mejoran significativamente la legibilidad y la comprensión de los interesados.
Próximos Pasos
Incorporar datos en tiempo real para el reequilibrio dinámico.
Explorar demografía de usuarios (edad, género) y modelos predictivos para pronóstico de demanda.
Expandir al dataset de 2025 cuando esté disponible.
Este informe reproducible demuestra habilidades en R (tidyverse, leaflet), limpieza de datos, EDA, visualización, dashboards interactivos (Tableau) e insights de negocio — listo para roles de analista de datos.
Ver el informe completo en línea (con mapas de calor interactivos):
Abrir
el Informe Ecobici 2024 en mi sitio web
(Versión interactiva con zoom, desplazamiento y tooltips — no requiere
descarga.)
Panel Interactivo
Explora el dataset completo de manera interactiva en Tableau
Public:
Ver
el Dashboard Ecobici 2024
Descargar Informe en PDF
Para una versión imprimible:
Descargar
PDF
(Informe completo con todas las visualizaciones e insights — 12
páginas)