Ejercicio de manipulación de datos y visualización de datos de subidas de paraderos del metro de Santiago.
Se utilizará:
readr
para la lectura de datos.dplyr
y tidy
para manipulación de información.ggplot2
para la visualización.stringr
para tratamiento de strings.#’library(readr)
library(dplyr)
library(ggplot2)
library(hrbrthemes)
library(viridis)
library(stringr)
library(tidyr)
library(purrr)
Los datos de _matrices de viaje son obtenidos de Directorio de Transporte Público: http://www.dtpm.gob.cl/index.php/2013-04-29-20-33-57/matrices-de-viaje.
dfsubidas <- read_csv2("data/2015.04_Subidas_paradero_mediahora_web.csv")
Primera inspección;
dfsubidas
## # A tibble: 358,543 × 3
## paraderosubida mediahora subidas_laboral_promedio
## <chr> <time> <chr>
## 1 ALCANTARA 05:30:00 2.6000000000000000
## 2 ALCANTARA 06:00:00 13.2000000000000000
## 3 ALCANTARA 06:30:00 53.4000000000000000
## 4 ALCANTARA 07:00:00 184.8000000000000000
## 5 ALCANTARA 07:30:00 364.0000000000000000
## 6 ALCANTARA 08:00:00 546.2000000000000000
## 7 ALCANTARA 08:30:00 478.6000000000000000
## 8 ALCANTARA 09:00:00 359.0000000000000000
## 9 ALCANTARA 09:30:00 275.4000000000000000
## 10 ALCANTARA 10:00:00 229.6000000000000000
## # ... with 358,533 more rows
La tabla contiene información de subidas promedios en días laborales por cada media hora. La variable subidas_laboral_promedio
se ha cargado como carácter en lugar de numérica.
dfsubidas <- mutate(dfsubidas, subidas_laboral_promedio = as.numeric(subidas_laboral_promedio))
dfsubidas
## # A tibble: 358,543 × 3
## paraderosubida mediahora subidas_laboral_promedio
## <chr> <time> <dbl>
## 1 ALCANTARA 05:30:00 2.6
## 2 ALCANTARA 06:00:00 13.2
## 3 ALCANTARA 06:30:00 53.4
## 4 ALCANTARA 07:00:00 184.8
## 5 ALCANTARA 07:30:00 364.0
## 6 ALCANTARA 08:00:00 546.2
## 7 ALCANTARA 08:30:00 478.6
## 8 ALCANTARA 09:00:00 359.0
## 9 ALCANTARA 09:30:00 275.4
## 10 ALCANTARA 10:00:00 229.6
## # ... with 358,533 more rows
Cuantos paraderos contiene la tabla:
count(dfsubidas, paraderosubida)
## # A tibble: 11,222 × 2
## paraderosubida n
## <chr> <int>
## 1 - 45
## 2 ALCANTARA 37
## 3 BAQUEDANO L1 37
## 4 BAQUEDANO L5 36
## 5 BARRANCAS 37
## 6 BELLAS ARTES 37
## 7 BELLAVISTA DE LA FLORIDA 37
## 8 BLANQUEADO 37
## 9 CAL Y CANTO 36
## 10 CAMINO AGRICOLA 37
## # ... with 11,212 more rows
Contiene 11222. Filtramos solamente paradas de metro.
set.seed(1234)
sample(dfsubidas$paraderosubida, 20)
## [1] "L-13-3-35-SN" "L-8-22-10-NS" "L-7-45-6-SN" "L-8-32-5-NS"
## [5] "T-27-224-NS-15" "PEDRERO" "E-20-189-PO-5" "L-21-18-20-OP"
## [9] "T-11-83-SN-10" "L-34-40-50-PO" "T-13-97-SN-35" "L-34-7-60-OP"
## [13] "L-23-36-15-SN" "T-33-264-SN-30" "L-23-6-20-OP" "T-23-376-NS-7"
## [17] "L-23-4-25-PO" "L-2-26-10-NS" "L-17-42-5-NS" "L-21-18-10-PO"
Luego de explorar un poco está columna se selecciona lo que no posea un string que comience con T, L, I o E y un guión:
dfsubidas <- filter(dfsubidas, !str_detect(paraderosubida, "^(T|L|I|E)?-"))
count(dfsubidas, paraderosubida)
## # A tibble: 106 × 2
## paraderosubida n
## <chr> <int>
## 1 ALCANTARA 37
## 2 BAQUEDANO L1 37
## 3 BAQUEDANO L5 36
## 4 BARRANCAS 37
## 5 BELLAS ARTES 37
## 6 BELLAVISTA DE LA FLORIDA 37
## 7 BLANQUEADO 37
## 8 CAL Y CANTO 36
## 9 CAMINO AGRICOLA 37
## 10 CARLOS VALDOVINOS 37
## # ... with 96 more rows
Y luego del filtros nos quedamos con 106 estaciones (de metro supuestamente). Sin embargo vemos que aparece Baquedano dos veces dado que es una estación de combinación. En esta oportunidad la consideraremos como una por lo que al nomnre de la estación removeremos la parte que hace distición a que línea es " L\\d"
donde "\\d"
es algún número.
Entonces removemos, agrupamos para sumar los casos de combinaciones:
dfsubidas <- dfsubidas %>%
mutate(paraderosubida = str_replace(paraderosubida, " L\\d$", "")) %>%
group_by(paraderosubida, mediahora) %>%
summarise(subidas_laboral_promedio = sum(subidas_laboral_promedio)) %>%
ungroup()
count(dfsubidas, paraderosubida)
## # A tibble: 101 × 2
## paraderosubida n
## <chr> <int>
## 1 ALCANTARA 37
## 2 BAQUEDANO 37
## 3 BARRANCAS 37
## 4 BELLAS ARTES 37
## 5 BELLAVISTA DE LA FLORIDA 37
## 6 BLANQUEADO 37
## 7 CAL Y CANTO 36
## 8 CAMINO AGRICOLA 37
## 9 CARLOS VALDOVINOS 37
## 10 CEMENTERIOS 37
## # ... with 91 more rows
;)!.
Ahora contemos si todas las estaciones contiene la misma cantidad de registros
dfsubidas %>%
count(paraderosubida) %>%
count(n)
## # A tibble: 3 × 2
## n nn
## <int> <int>
## 1 36 38
## 2 37 62
## 3 38 1
Existe una estación que contiene 38 registros y otras 38 estaciones que contiene 36 regitros.
dfsubidas %>%
count(mediahora)
## # A tibble: 38 × 2
## mediahora n
## <time> <int>
## 1 00:00:00 1
## 2 05:30:00 101
## 3 06:00:00 101
## 4 06:30:00 101
## 5 07:00:00 101
## 6 07:30:00 101
## 7 08:00:00 101
## 8 08:30:00 101
## 9 09:00:00 101
## 10 09:30:00 101
## # ... with 28 more rows
dfsubidas %>%
count(mediahora) %>%
filter(n != 101)
## # A tibble: 2 × 2
## mediahora n
## <time> <int>
## 1 00:00:00 1
## 2 23:30:00 63
# Eliminaremos las 12AM.
dfsubidas <- filter(dfsubidas, mediahora != 0)
# dfsubidas <- complete(dfsubidas, paraderosubida, mediahora,
# fill = list(subidas_laboral_promedio = 0))
Ahora visualizaremos los registros por líneas y veremos la tencendia a través de un suavizamientos:
gg <- ggplot(dfsubidas) +
geom_line(aes(mediahora, subidas_laboral_promedio,
group = paraderosubida), alpha = 0.25) +
geom_smooth(aes(mediahora, subidas_laboral_promedio), size = 1.3) +
scale_x_time() +
scale_y_comma()
gg
Se observa lo esperado: mucha gente ingresa a las 8 y 18.30 app además de un leve peak a las 13.00 horas.
Por diversión agregaremos las horas puntas:
library(lubridate)
dfhorarios <- data_frame(
xmin = c(hms("7:00:00"), hms("18:00:00")),
xmax = c(hms("8:59:59"), hms("19:59:69")),
ymin = c(0, 0),
ymax = rep(7000, 2),
g = c(1, 2)
)
gg <- gg +
geom_rect(data = dfhorarios,
aes(xmin = xmin, xmax = xmax,
ymin = ymin, ymax = ymax), alpha = 0.2)
gg
## Agrupando Estaciones
Vemos que algunas estaciones
dfsubidas2 <- spread(dfsubidas, mediahora, subidas_laboral_promedio)
dfsubidas2
## # A tibble: 101 × 38
## paraderosubida `05:30:00` `06:00:00` `06:30:00` `07:00:00`
## * <chr> <dbl> <dbl> <dbl> <dbl>
## 1 ALCANTARA 2.6 13.2 53.4 184.8
## 2 BAQUEDANO 88.0 132.6 234.6 493.4
## 3 BARRANCAS 37.0 195.4 406.4 736.8
## 4 BELLAS ARTES 6.6 37.0 92.2 177.6
## 5 BELLAVISTA DE LA FLORIDA 157.6 297.8 565.8 1113.6
## 6 BLANQUEADO 35.8 199.6 411.4 646.4
## 7 CAL Y CANTO 103.0 575.2 1281.0 2309.0
## 8 CAMINO AGRICOLA 38.2 113.2 281.6 530.6
## 9 CARLOS VALDOVINOS 46.2 113.0 210.4 342.4
## 10 CEMENTERIOS 20.8 78.4 167.6 249.8
## # ... with 91 more rows, and 33 more variables: `07:30:00` <dbl>,
## # `08:00:00` <dbl>, `08:30:00` <dbl>, `09:00:00` <dbl>,
## # `09:30:00` <dbl>, `10:00:00` <dbl>, `10:30:00` <dbl>,
## # `11:00:00` <dbl>, `11:30:00` <dbl>, `12:00:00` <dbl>,
## # `12:30:00` <dbl>, `13:00:00` <dbl>, `13:30:00` <dbl>,
## # `14:00:00` <dbl>, `14:30:00` <dbl>, `15:00:00` <dbl>,
## # `15:30:00` <dbl>, `16:00:00` <dbl>, `16:30:00` <dbl>,
## # `17:00:00` <dbl>, `17:30:00` <dbl>, `18:00:00` <dbl>,
## # `18:30:00` <dbl>, `19:00:00` <dbl>, `19:30:00` <dbl>,
## # `20:00:00` <dbl>, `20:30:00` <dbl>, `21:00:00` <dbl>,
## # `21:30:00` <dbl>, `22:00:00` <dbl>, `22:30:00` <dbl>,
## # `23:00:00` <dbl>, `23:30:00` <dbl>
dfsubidas3 <- select(dfsubidas2, -1) %>%
mutate_all(function(x) ifelse(is.na(x), 0, x)) %>%
mutate_all(scale)
kmeans <- map_df(1:10, function(k){ # k <- 6
set.seed(123)
kmod <- kmeans(dfsubidas3, centers = k)
data_frame(k = k, wcss = 1 - kmod$betweenss/kmod$totss, kmod = list(kmod))
})
ggplot(kmeans) +
geom_line(aes(k, wcss)) +
scale_y_continuous(labels = scales::percent) +
scale_x_continuous(breaks = seq(1:10), minor_breaks = NULL)
K <- 4
dfsubidas2 <- mutate(dfsubidas2, grupo = kmeans$kmod[[K]]$cluster)
dfsubidas <- left_join(dfsubidas, select(dfsubidas2, paraderosubida, grupo))
dfsubidas
## # A tibble: 3,699 × 4
## paraderosubida mediahora subidas_laboral_promedio grupo
## <chr> <time> <dbl> <int>
## 1 ALCANTARA 05:30:00 2.6 3
## 2 ALCANTARA 06:00:00 13.2 3
## 3 ALCANTARA 06:30:00 53.4 3
## 4 ALCANTARA 07:00:00 184.8 3
## 5 ALCANTARA 07:30:00 364.0 3
## 6 ALCANTARA 08:00:00 546.2 3
## 7 ALCANTARA 08:30:00 478.6 3
## 8 ALCANTARA 09:00:00 359.0 3
## 9 ALCANTARA 09:30:00 275.4 3
## 10 ALCANTARA 10:00:00 229.6 3
## # ... with 3,689 more rows
ggplot(dfsubidas, aes(mediahora, subidas_laboral_promedio)) +
geom_line(aes(group = paraderosubida), alpha = 0.15) +
geom_smooth(aes(group = grupo, color = factor(grupo))) +
scale_color_viridis(discrete = TRUE) +
scale_x_time() +
facet_wrap(~grupo) +
theme(legend.position = "none")
routes <- read_csv("data/routes.txt")
trips <- read_csv("data/trips.txt")
stops <- read_csv("data/stops.txt")
shapes <-read_csv("data/shapes.txt")
stops_metro <- stops %>%
filter(!grepl("\\d", stop_id)) %>%
mutate(stop_url = basename(stop_url))
routes_metro <- filter(routes, grepl("^L\\d",route_id))
shapes_metro <- routes %>%
filter(grepl("^L\\d",route_id)) %>%
semi_join(trips, .) %>%
semi_join(shapes, .) %>%
### IMPORTANTE
filter(str_detect(shape_id, "-I")) %>%
mutate(shape_id2 = str_replace(shape_id, "-I", ""))
colors_metro <- distinct(shapes, shape_id) %>%
left_join(distinct(trips, shape_id, route_id)) %>%
left_join(distinct(routes, route_id, route_color)) %>%
semi_join(shapes_metro) %>%
mutate(route_color = paste0("#", route_color))
str_to_id2 <- function(x) {
x %>%
str_trim() %>%
str_to_lower() %>%
str_replace_all("\\s+", "_") %>%
str_replace_all("\\s+de\\s+", "") %>%
str_replace_all("á", "a") %>%
str_replace_all("é", "e") %>%
str_replace_all("í", "i") %>%
str_replace_all("ó", "o") %>%
str_replace_all("ú", "u") %>%
str_replace_all("ñ", "n") %>%
str_replace_all("`", "") %>%
str_replace_all("_de_", "_") %>%
str_replace_all("rondizonni", "rondizzoni")
}
dfsubidas2 <- mutate(dfsubidas2, id = str_to_id2(paraderosubida))
stops_metro_data <- stops_metro %>%
mutate(id = str_to_id2(stop_name)) %>%
left_join(select(dfsubidas2, grupo, id))
ggplot()+
geom_path(data = shapes_metro,
aes(x = shape_pt_lon, y = shape_pt_lat, group = shape_id, color = shape_id),
size = 1.2) +
geom_point(data = stops_metro_data,
aes(x = stop_lon, y = stop_lat, color = factor(grupo)),
size = 2, alpha = 0.95) +
scale_color_manual(values = c(colors_metro$route_color, viridis(K))) +
# scale_color_viridis(discrete = TRUE) +
facet_wrap(~grupo) +
scale_x_continuous(breaks = NULL) +
scale_y_continuous(breaks = NULL) +
coord_fixed() +
theme_minimal() +
theme(legend.position = "left")