Planteamiento del Problema

A partir de la base de datos “EncuestaOrigenDestino.xlsx” que contiene información sobre los viajes de personas realizados en la ciudad de Cali durante los meses de mayo y junio de 2015, se deben realizar 8 mapas que corresponden a:

  1. Origen del viaje.
  2. Origen del viaje por tipo de vehículo bicicleta.
  3. Origen del viaje por tipo de vehículo moto.
  4. Origen del viaje por tipo de vehículo automóvil.
  5. Destino del viaje.
  6. Destino del viaje por tipo de vehículo bicicleta.
  7. Destino del viaje por tipo de vehículo moto.
  8. Destino del viaje por tipo de vehículo automóvil.

Análisis exploratorio y preparación de datos

Se realiza una verificación preliminar de la información, de acuerdo a los siguientes pasos: 1. Cargue y verificación del archivo shapefile. 2. Visualización de mapa de comunas, verificando su correcta georreferenciación. 3. Cargue y verificación del archivo excel. 4. Limpieza y recodificación de los nombres de las columnas 5. Verificación de datos faltantes

Cargue y visualización de Comunas en formato shapefile

#Importar shapefile comunas
library(sf)
require(raster)
require(rgdal)
require(leaflet)

comunas=st_read(("D:/MaestriaCienciaDatos/S2_AnalisisInfoGeografica/M1U1_Introduccion/Casos/cali/Comunas.shp"))
## Reading layer `Comunas' from data source 
##   `D:\MaestriaCienciaDatos\S2_AnalisisInfoGeografica\M1U1_Introduccion\Casos\cali\Comunas.shp' 
##   using driver `ESRI Shapefile'
## Simple feature collection with 22 features and 4 fields
## Geometry type: POLYGON
## Dimension:     XY
## Bounding box:  xmin: 1053868 ymin: 860190.2 xmax: 1068492 ymax: 879441.5
## Projected CRS: MAGNA_Colombia_Cali
comunas
## Simple feature collection with 22 features and 4 fields
## Geometry type: POLYGON
## Dimension:     XY
## Bounding box:  xmin: 1053868 ymin: 860190.2 xmax: 1068492 ymax: 879441.5
## Projected CRS: MAGNA_Colombia_Cali
## First 10 features:
##    OBJECTID gid comuna    nombre                       geometry
## 1         1 107      2  Comuna 2 POLYGON ((1059648 874236.3,...
## 2         2 108      1  Comuna 1 POLYGON ((1054094 875172.8,...
## 3         3 109      3  Comuna 3 POLYGON ((1061757 874615.5,...
## 4         4 110     19 Comuna 19 POLYGON ((1057817 873269.4,...
## 5         5 103     15 Comuna 15 POLYGON ((1065485 869864.1,...
## 6         6 104     17 Comuna 17 POLYGON ((1061675 868320.9,...
## 7         7 105     18 Comuna 18 POLYGON ((1059061 867223.6,...
## 8         8 106     22 Comuna 22 POLYGON ((1059486 864976.4,...
## 9         9  89      6  Comuna 6 POLYGON ((1065143 879409.5,...
## 10       10  90      4  Comuna 4 POLYGON ((1063833 877507.1,...
comunas <- st_transform(comunas, crs = 4326)

leaflet(comunas) %>%
  addProviderTiles("OpenStreetMap") %>%  # fondo básico
  addPolygons(
    color = "blue", weight = 1, fillColor = "lightblue", fillOpacity = 0.5,
    popup = ~paste0(nombre)  
  )



Cargue y limpieza de registros origen - destino en formato excel

library(readxl)

#Importar tabla excel de Origen-Destino
od=read_excel("D:/MaestriaCienciaDatos/S2_AnalisisInfoGeografica/M1U1_Introduccion/Casos/EncuestaOrigenDestino.xlsx", 
    sheet = "Hoja1",.name_repair = "minimal")

#Limpiar la codificación de los nombres de las columnas
names(od) <- gsub("\\s+", "_", names(od))   # reemplaza espacios por guion bajo
names(od) <- gsub("[^A-Za-z0-9_]", "", names(od))  # elimina símbolos no válidos

# hacer los nombres únicos automáticamente
names(od) <- make.names(names(od), unique = TRUE)
head(od)
## # A tibble: 6 × 28
##   FECHA               ID_ESTACIN ESTACIN   ACCESO MOVIMIENTO Hora_de_Encuesta   
##   <dttm>                   <dbl> <chr>     <chr>  <chr>      <dttm>             
## 1 2015-06-01 00:00:00          1 Avenida … NORTE  MOV 1      1899-12-31 06:10:00
## 2 2015-06-01 00:00:00          1 Avenida … NORTE  MOV 1      1899-12-31 06:11:00
## 3 2015-06-01 00:00:00          1 Avenida … NORTE  MOV 1      1899-12-31 06:12:00
## 4 2015-06-01 00:00:00          1 Avenida … NORTE  MOV 1      1899-12-31 06:13:00
## 5 2015-06-01 00:00:00          1 Avenida … NORTE  MOV 1      1899-12-31 06:14:00
## 6 2015-06-01 00:00:00          1 Avenida … NORTE  MOV 1      1899-12-31 06:15:00
## # ℹ 22 more variables: MUNICIPIO <chr>,
## #   DEPARTAMENTO__LOCALIDAD__COMUNA__DISTRITO__BARRIO__VEREDA__HITO__DIRECCIN <chr>,
## #   Codigo_Origen_SDG <chr>, QUE_ESTABA_HACIENDO_EN_ESE_LUGAR <dbl>,
## #   MUNICIPIO.1 <chr>,
## #   DEPARTAMENTO__LOCALIDAD__COMUNA__DISTRITO__BARRIO__VEREDA__HITO__DIRECCIN.1 <chr>,
## #   Codigo_Destino_SDG <chr>, QUE_VA_HACER_A_ESE_LUGAR <dbl>,
## #   ESTRATO_EN_SU_VIVIENDA <dbl>, …
names(od)
##  [1] "FECHA"                                                                      
##  [2] "ID_ESTACIN"                                                                 
##  [3] "ESTACIN"                                                                    
##  [4] "ACCESO"                                                                     
##  [5] "MOVIMIENTO"                                                                 
##  [6] "Hora_de_Encuesta"                                                           
##  [7] "MUNICIPIO"                                                                  
##  [8] "DEPARTAMENTO__LOCALIDAD__COMUNA__DISTRITO__BARRIO__VEREDA__HITO__DIRECCIN"  
##  [9] "Codigo_Origen_SDG"                                                          
## [10] "QUE_ESTABA_HACIENDO_EN_ESE_LUGAR"                                           
## [11] "MUNICIPIO.1"                                                                
## [12] "DEPARTAMENTO__LOCALIDAD__COMUNA__DISTRITO__BARRIO__VEREDA__HITO__DIRECCIN.1"
## [13] "Codigo_Destino_SDG"                                                         
## [14] "QUE_VA_HACER_A_ESE_LUGAR"                                                   
## [15] "ESTRATO_EN_SU_VIVIENDA"                                                     
## [16] "DISPONIA_DE_UN_VEHCULO_PARA_REALIZAR_ESTE_DESPLAZAMIENTO"                   
## [17] "OTRO_CUL"                                                                   
## [18] "ANTES"                                                                      
## [19] "DESPUES"                                                                    
## [20] "EDAD"                                                                       
## [21] "SEXO"                                                                       
## [22] "PERSONAS_EN_EL_VEHCULO"                                                     
## [23] "TIPO_DE_VEHCULO"                                                            
## [24] "OTRO_CUL.1"                                                                 
## [25] "TIPO_DE_VIAJERO"                                                            
## [26] "comuna_origen"                                                              
## [27] "comuna_destino"                                                             
## [28] "Intracomuna"

Cantidad de registros

nrow(od)
## [1] 35054

Verificación de datos faltantes

library(kableExtra)

#Calculando datos faltantes
Datos_faltantes <- data.frame(colnames(od), sapply(od, function(x) sum(is.na(x))))
Datos_faltantes <- Datos_faltantes[c(23, 26:27), ]

#Limpiando Dataframe
rownames(Datos_faltantes) <- NULL
colnames(Datos_faltantes) <- c("Variable", "Datos Faltantes")

#Presentando información en formato tabla
kable_classic(kbl(Datos_faltantes, caption = "<center><b>Tabla 1. Datos Faltantes por Variable</b></center>"), full_width = F)
Tabla 1. Datos Faltantes por Variable
Variable Datos Faltantes
TIPO_DE_VEHCULO 115
comuna_origen 0
comuna_destino 0

La única variable que presenta datos faltantes es Tipo de Vehículo, teniendo en cuenta que representan tan solo el 0,33% de los datos, no se realizará ninguna imputación.

Conteo por comuna según origen y tipo de vehículo

library(dplyr)

#Convertir las columnas comuna_origen y comuna_destino de character a integer
od <- od %>%
  mutate(comuna_origen = as.integer(comuna_origen)) %>%
  mutate(comuna_destino = as.integer(comuna_destino))

#Conteo por comuna según origen
cnt_origen <- od %>%
  count(comuna_origen) #%>% 
  #filter(!is.na(comuna_origen)) #Se omiten NA equivalentes a fura de cali

#Conteo por comuna según origen y tipo de vehículo: bicicleta, moto o automovil.
cnt_vehiculo <- od %>% 
  filter(TIPO_DE_VEHCULO %in% c(1, 2, 3)) %>% # 👈 filtra solo los tipos 1, 2 y 3 
  group_by(comuna_origen, TIPO_DE_VEHCULO) %>% 
  summarise(total = n(), .groups = "drop") %>% # .groups = "drop" evita advertencias 
  tidyr::pivot_wider( #Convierte los tipos de vehículo en columnas. 
    names_from = TIPO_DE_VEHCULO, 
    values_from = total, 
    names_prefix = "vehiculo_" 
    ) #%>% 
  #filter(!is.na(comuna_origen))#Se omiten NA equivalentes a fura de cali

cnt_origen %>%
  knitr::kable() %>%
  kable_classic(full_width = FALSE)
comuna_origen n
0 672
1 794
2 2968
3 2121
4 1493
5 664
6 998
7 734
8 1124
9 952
10 1401
11 925
12 348
13 1238
14 685
15 1171
16 993
17 2377
18 1536
19 2850
20 733
21 818
22 1153
NA 6306
cnt_vehiculo %>%
  knitr::kable() %>%
  kable_classic(full_width = FALSE)
comuna_origen vehiculo_1 vehiculo_2 vehiculo_3
0 43 259 317
1 36 375 301
2 159 1414 1121
3 99 970 854
4 74 720 551
5 38 319 241
6 44 473 389
7 35 350 283
8 52 552 420
9 53 413 382
10 82 675 529
11 52 431 361
12 14 176 123
13 76 554 486
14 37 310 272
15 70 536 456
16 73 450 385
17 141 1136 899
18 111 746 559
19 141 1280 1165
20 46 339 272
21 44 378 328
22 55 515 489
NA 156 2706 2917

En el conteo por comuna se evidencian dos tipos de comuna que salen del análisis. Las que tienen valor de cero (0) y las que se presentan como NA. Teniendo en cuenta que se convirtió el tipo de datos de las comunas a entero para facilitar el join con el shapefile, los NA corresponden a los datos clasificados originalmente como Fuera de Cali y los ceros son registros sin información que si se imputaran por la moda quedarían clasificados como Fuera de Cali y saldrían del análisis. Por este motivo no se realiza ningún proceso y se trabaja únicamente con las 22 comunas válidas.

Integración en shapefile de conteos según origen

#Integración de datos
shape_joined <- comunas %>%
  left_join(cnt_origen, by  = c("comuna" = "comuna_origen")) %>%
  left_join(cnt_vehiculo, by = c("comuna" = "comuna_origen"))
#Renombrar columnas
shape_joined <- shape_joined %>%
  rename(
    origen = n,
    origen_bici = vehiculo_1,
    origen_moto = vehiculo_2,
    origen_auto = vehiculo_3
  )
head(shape_joined)
## Simple feature collection with 6 features and 8 fields
## Geometry type: POLYGON
## Dimension:     XY
## Bounding box:  xmin: -76.59284 ymin: 3.362385 xmax: -76.48289 ymax: 3.498517
## Geodetic CRS:  WGS 84
##   OBJECTID gid comuna    nombre origen origen_bici origen_moto origen_auto
## 1        1 107      2  Comuna 2   2968         159        1414        1121
## 2        2 108      1  Comuna 1    794          36         375         301
## 3        3 109      3  Comuna 3   2121          99         970         854
## 4        4 110     19 Comuna 19   2850         141        1280        1165
## 5        5 103     15 Comuna 15   1171          70         536         456
## 6        6 104     17 Comuna 17   2377         141        1136         899
##                         geometry
## 1 POLYGON ((-76.54083 3.45880...
## 2 POLYGON ((-76.5908 3.467272...
## 3 POLYGON ((-76.52185 3.46223...
## 4 POLYGON ((-76.5573 3.450063...
## 5 POLYGON ((-76.48831 3.41927...
## 6 POLYGON ((-76.52258 3.40532...

Conteo por comuna según destino y tipo de vehículo

#Conteo por comuna según destino
cnt_destino <- od %>%
  count(comuna_destino)

#Conteo por comuna según destino y tipo de vehículo: bicicleta, moto o automovil.
cnt_vehiculod <- od %>%
  filter(TIPO_DE_VEHCULO %in% c(1, 2, 3)) %>%   # 👈 filtra solo los tipos 1, 2 y 3
  group_by(comuna_destino, TIPO_DE_VEHCULO) %>%
  summarise(total = n(), .groups = "drop") %>%   # .groups = "drop" evita advertencias
  tidyr::pivot_wider(                            #Convierte los tipos de vehículo en columnas.
    names_from = TIPO_DE_VEHCULO,
    values_from = total,
    names_prefix = "vehiculo_"
  )  

cnt_destino %>%
  knitr::kable() %>%
  kable_classic(full_width = FALSE)
comuna_destino n
0 788
1 230
2 4810
3 3859
4 1856
5 522
6 716
7 748
8 1025
9 1279
10 927
11 564
12 246
13 673
14 379
15 579
16 743
17 2164
18 662
19 3158
20 351
21 515
22 1860
NA 6400
cnt_vehiculod %>%
  knitr::kable() %>%
  kable_classic(full_width = FALSE)
comuna_destino vehiculo_1 vehiculo_2 vehiculo_3
0 46 390 280
1 12 112 86
2 218 2177 2006
3 189 1734 1557
4 85 846 757
5 41 215 225
6 34 323 275
7 41 353 286
8 54 470 403
9 65 608 489
10 43 419 384
11 29 254 239
12 15 128 85
13 33 346 226
14 22 188 138
15 20 271 245
16 35 327 321
17 115 927 959
18 31 302 276
19 147 1421 1302
20 25 151 144
21 26 243 198
22 100 911 694
NA 305 2961 2525

De igual forma que para el conteo desde el origen, en este caso tampoco se realiza ningún proceso de imputación y se trabaja únicamente con las 22 comunas válidas.

Integración en shapefile de conteos según destino

#Integración de datos
shape_joined2 <- shape_joined %>%
  left_join(cnt_destino, by  = c("comuna" = "comuna_destino")) %>%
  left_join(cnt_vehiculod, by = c("comuna" = "comuna_destino"))

#Renombrar columnas
shape_joined2 <- shape_joined2 %>%
  rename(
    destino = n,
    destino_bici = vehiculo_1,
    destino_moto = vehiculo_2,
    destino_auto = vehiculo_3
  )
head(shape_joined2)
## Simple feature collection with 6 features and 12 fields
## Geometry type: POLYGON
## Dimension:     XY
## Bounding box:  xmin: -76.59284 ymin: 3.362385 xmax: -76.48289 ymax: 3.498517
## Geodetic CRS:  WGS 84
##   OBJECTID gid comuna    nombre origen origen_bici origen_moto origen_auto
## 1        1 107      2  Comuna 2   2968         159        1414        1121
## 2        2 108      1  Comuna 1    794          36         375         301
## 3        3 109      3  Comuna 3   2121          99         970         854
## 4        4 110     19 Comuna 19   2850         141        1280        1165
## 5        5 103     15 Comuna 15   1171          70         536         456
## 6        6 104     17 Comuna 17   2377         141        1136         899
##   destino destino_bici destino_moto destino_auto                       geometry
## 1    4810          218         2177         2006 POLYGON ((-76.54083 3.45880...
## 2     230           12          112           86 POLYGON ((-76.5908 3.467272...
## 3    3859          189         1734         1557 POLYGON ((-76.52185 3.46223...
## 4    3158          147         1421         1302 POLYGON ((-76.5573 3.450063...
## 5     579           20          271          245 POLYGON ((-76.48831 3.41927...
## 6    2164          115          927          959 POLYGON ((-76.52258 3.40532...

Mapeo de la movilidad de personas en la ciudad de Cali

Comparación de mapas Origen - Destino

library(tmap)

# Busqueda del centroide para localización de etiquetas. Crear puntos dentro de cada polígono
centros <- comunas %>%
  st_point_on_surface()

# Activar modo de visualización interactiva o estática
tmap_mode("plot") # o "view" si quieres sobre Google Maps

# ---- Crear mapas por tipo de vehículo ----

# Origen-Destino
map_o <- tm_shape(shape_joined2) +
  tm_polygons("origen", 
              palette = "Purples",
              style = "quantile",
              title = "Origen") +
  tm_shape(centros) +
  tm_text("comuna", size = 1, col = "black", fontface = "bold") +
  tm_layout(legend.outside = TRUE)

map_d <- tm_shape(shape_joined2) +
  tm_polygons("destino", 
              palette = "Purples",
              style = "quantile",
              title = "Destino") +
  tm_shape(centros) +
  tm_text("comuna", size = 1, col = "black", fontface = "bold") +
  tm_layout(legend.outside = TRUE)

# Bicicleta
map_v1_origen <- tm_shape(shape_joined2) +
  tm_polygons("origen_bici",
              palette = "Greens",
              style = "quantile",
              title = "Bicicleta - Origen") +
  tm_shape(centros) +
  tm_text("comuna", size = 1, col = "black", fontface = "bold") +
  tm_layout(legend.outside = TRUE)

map_v1_destino <- tm_shape(shape_joined2) +
  tm_polygons("destino_bici",
              palette = "Greens",
              style = "quantile",
              title = "Bicicleta - Destino") +
  tm_shape(centros) +
  tm_text("comuna", size = 1, col = "black", fontface = "bold") +
  tm_layout(legend.outside = TRUE)

# Moto
map_v2_origen <- tm_shape(shape_joined2) +
  tm_polygons("origen_moto",
              palette = "Blues",
              style = "quantile",
              title = "Moto - Origen") +
  tm_shape(centros) +
  tm_text("comuna", size = 1, col = "black", fontface = "bold") +
  tm_layout(legend.outside = TRUE)

map_v2_destino <- tm_shape(shape_joined2) +
  tm_polygons("destino_moto",
              palette = "Blues",
              style = "quantile",
              title = "Moto - Destino") +
  tm_shape(centros) +
  tm_text("comuna", size = 1, col = "black", fontface = "bold") +
  tm_layout(legend.outside = TRUE)

# Vehículo 3
map_v3_origen <- tm_shape(shape_joined2) +
  tm_polygons("origen_auto",
              palette = "Oranges",
              style = "quantile",
              title = "Automovil - Origen") +
  tm_shape(centros) +
  tm_text("comuna", size = 1, col = "black", fontface = "bold") +
  tm_layout(legend.outside = TRUE)

map_v3_destino <- tm_shape(shape_joined2) +
  tm_polygons("destino_auto",
              palette = "Oranges",
              style = "quantile",
              title = "Automovil - Destino") +
  tm_shape(centros) +
  tm_text("comuna", size = 1, col = "black", fontface = "bold") +
  tm_layout(legend.outside = TRUE)

ajuste_leyenda <- tm_layout(
  legend.outside = FALSE,          # leyenda dentro del mapa
  legend.position = c("right", "bottom"),  # posición interna
  legend.bg.color = "white",
  legend.bg.alpha = 0.6,
  legend.text.size = 1.2,
  legend.title.size = 1.4
)

map_o <- map_o + ajuste_leyenda
map_d <- map_d + ajuste_leyenda
map_v1_origen <- map_v1_origen + ajuste_leyenda
map_v1_destino <- map_v1_destino + ajuste_leyenda
map_v2_origen <- map_v2_origen + ajuste_leyenda
map_v2_destino <- map_v2_destino + ajuste_leyenda
map_v3_origen <- map_v3_origen + ajuste_leyenda
map_v3_destino <- map_v3_destino + ajuste_leyenda

tmap_arrange(
  map_o, map_d,
  ncol = 2, 
  asp = 0.7
)

Comparación de mapas Origen - Destino - Tipo de vehículo: Bicicleta

tmap_arrange(
  map_v1_origen, map_v1_destino, 
  ncol = 2, 
  asp = 0.7
)

Comparación de mapas Origen - Destino - Tipo de vehículo: Moto

tmap_arrange(
  map_v2_origen, map_v2_destino, 
  ncol = 2, 
  asp = 0.7
)

Comparación de mapas Origen - Destino - Tipo de vehículo: Automovil

tmap_arrange(
  map_v3_origen, map_v3_destino, 
  ncol = 2, 
  asp = 0.7
)

Interpretación de los resultados

Conclusiones

Algunas hipoótesis que se podrían plantear de estos resultados son: