En el siguiente informe vamos a analizar el dataset de Origen vs Destinos de Cali, en el que se nos muestra la cantidad de viajes dentro de Cali. Se discriminan los datos por tipo de vehículo, si el viaje empieza y termina dentro o fuera de Cali, y si es dentro de Cali, por cuál comuna empieza o termina el viaje de dicho vehículo.

En el siguiente informe lo que nos interesa es el movimiento dentro de Cali, se omiten los viajes hacia fuera o desde fuera de Cali.

Se presentan 8 mapas de calor de la siguiente manera:

  1. Número de origenes por comuna de todos los tipos de vehículos.
  2. Número de destinos por comuna de todos los tipos de vehículos.
  3. Número de origenes por comuna de todas las motocicletas.
  4. Número de destinos por comuna de todas las motocicletas.
  5. Número de origenes por comuna de todas las bicicletas.
  6. Número de destinos por comuna de todas las bicicletas.
  7. Número de origenes por comuna de todas los automoviles.
  8. Número de destinos por comuna de todas las automoviles.

Empezamos primero a tratar los datos que se nos ha otorgado via Excel. Anteriormente el Excel proporcionado fue convertido a CSV para un mejor tratamiento.

Cargamos los archivos para guardarlos como dataframe:

OrigenDestinoCSV <- read.csv("D:/Users/edier88/Downloads/Casos/EncuestaOrigenDestino.csv", stringsAsFactors = FALSE)

Como se dijo anteriormente, solamente tenemos en cuenta los movimientos que se hacen dentro de Cali:

OrigenDestinoCali=subset(OrigenDestinoCSV, OrigenDestinoCSV$MUNICIPIO=="CALI")
OrigenDestinoCali=subset(OrigenDestinoCali, OrigenDestinoCali$MUNICIPIO.1=="CALI")

Verificamos el conjunto de valores de origen y destino para saber cuáles nos sirven y cuáles no

table(OrigenDestinoCali$comuna.origen)
## 
##             0            01            02            03            04 
##           284           658          2381          1708          1261 
##            05            06            07            08            09 
##           553           835           612           912           791 
##            10            11            12            13            14 
##          1176           760           278          1095           600 
##            15            16            17            18            19 
##          1022           869          1884          1289          2370 
##            20            21            22 Fuera de Cali 
##           625           733          1018           812
table(OrigenDestinoCali$comuna.destino)
## 
##             0            01            02            03            04 
##           230           191          3940          3021          1553 
##            05            06            07            08            09 
##           454           587           629           854          1116 
##            10            11            12            13            14 
##           772           499           217           588           326 
##            15            16            17            18            19 
##           496           680          1688           544          2557 
##            20            21            22 Fuera de Cali 
##           318           460          1644          1162

Definitivamente hay valores que no nos sirven para el análisis, eliminamos las columnas que indican valores de “0” y de “Fuera de Cali”

OrigenDestinoCali <- OrigenDestinoCali[OrigenDestinoCali$comuna.origen != "0", ]
OrigenDestinoCali <- OrigenDestinoCali[OrigenDestinoCali$comuna.origen != "Fuera de Cali", ]

OrigenDestinoCali <- OrigenDestinoCali[OrigenDestinoCali$comuna.destino != "0", ]
OrigenDestinoCali <- OrigenDestinoCali[OrigenDestinoCali$comuna.destino != "Fuera de Cali", ]

Ahora vemos que los valores son los que necesitamos (ya no hay datos en “0” o que indican “Fuera de Cali”):

table(OrigenDestinoCali$comuna.origen)
## 
##   01   02   03   04   05   06   07   08   09   10   11   12   13   14   15   16 
##  626 2249 1608 1193  521  796  583  862  737 1094  717  257 1031  574  974  836 
##   17   18   19   20   21   22 
## 1762 1208 2238  599  693  979
table(OrigenDestinoCali$comuna.destino)
## 
##   01   02   03   04   05   06   07   08   09   10   11   12   13   14   15   16 
##  187 3771 2881 1496  440  570  598  830 1055  741  483  207  560  316  481  645 
##   17   18   19   20   21   22 
## 1615  526 2438  303  434 1560

Ahora ya estamos seguros de que sólo tenemos comunas de cali tanto en origen como en destino

Cargamos el shapefile de comunas:

comunas = shapefile("D:/Users/edier88/Downloads/datosEncuentro2/datosEncuentro2/Comuna.shp")
crs(comunas)
## Coordinate Reference System:
## Deprecated Proj.4 representation: +proj=longlat +datum=WGS84 +no_defs 
## WKT2 2019 representation:
## GEOGCRS["unknown",
##     DATUM["World Geodetic System 1984",
##         ELLIPSOID["WGS 84",6378137,298.257223563,
##             LENGTHUNIT["metre",1]],
##         ID["EPSG",6326]],
##     PRIMEM["Greenwich",0,
##         ANGLEUNIT["degree",0.0174532925199433],
##         ID["EPSG",8901]],
##     CS[ellipsoidal,2],
##         AXIS["longitude",east,
##             ORDER[1],
##             ANGLEUNIT["degree",0.0174532925199433,
##                 ID["EPSG",9122]]],
##         AXIS["latitude",north,
##             ORDER[2],
##             ANGLEUNIT["degree",0.0174532925199433,
##                 ID["EPSG",9122]]]]
st_crs(comunas)
## Coordinate Reference System:
##   User input: +proj=longlat +datum=WGS84 +no_defs 
##   wkt:
## GEOGCRS["unknown",
##     DATUM["World Geodetic System 1984",
##         ELLIPSOID["WGS 84",6378137,298.257223563,
##             LENGTHUNIT["metre",1]],
##         ID["EPSG",6326]],
##     PRIMEM["Greenwich",0,
##         ANGLEUNIT["degree",0.0174532925199433],
##         ID["EPSG",8901]],
##     CS[ellipsoidal,2],
##         AXIS["longitude",east,
##             ORDER[1],
##             ANGLEUNIT["degree",0.0174532925199433,
##                 ID["EPSG",9122]]],
##         AXIS["latitude",north,
##             ORDER[2],
##             ANGLEUNIT["degree",0.0174532925199433,
##                 ID["EPSG",9122]]]]

Nuestro dataframe de origen/destino no tiene coordenadas, por lo que vamos a averiguar las coordenadas exactas de cada comuna para ponerlas en cada registro de nuestro dataframe.

Vamos a hacer esto calculando los centroides de cada polígono de nuestro shapefile, cada polígono es una comuna, por lo que averiguando su centroide podremos saber las coordenadas centrales de cada comuna, es decir, el centroide de cada comuna será su coordenada central:

# Se convierte a objeto sf
comunas_sf <- st_as_sf(comunas)

# se aplican y calculan los centroides
centroids_sf <- st_centroid(comunas_sf)
## Warning: st_centroid assumes attributes are constant over geometries
# Se extraen coordenadas y los números de las comunas
centroid_coords_comunas <- cbind(
  comuna = comunas_sf$comuna,
  st_coordinates(centroids_sf) %>% 
    as.data.frame() %>% 
    rename(longitude = X, latitude = Y)
)

Los centroides:

centroid_coords_comunas

Miramos que los index tienen un valor y la variable comuna otro, la idea es que el index sea el mismo numero del de la comuna así que igualaremos los números de los index a los de las comunas:

rownames(centroid_coords_comunas) <- centroid_coords_comunas$comuna
centroid_coords_comunas

Organizamos el dataset para que las comunas aparezcan en orden ascendente:

centroid_coords_comunas <- centroid_coords_comunas[order(centroid_coords_comunas$comuna, decreasing = FALSE),]
centroid_coords_comunas

Revisamos gráficamente cómo estan los puntos centrales (centroides) en cada comuna:

centroides = SpatialPointsDataFrame(coords = centroid_coords_comunas[,2:3],
                                    data = centroid_coords_comunas, proj4string = crs(comunas))

centroides
## class       : SpatialPointsDataFrame 
## features    : 22 
## extent      : -76.5668, -76.4709, 3.350728, 3.485557  (xmin, xmax, ymin, ymax)
## crs         : +proj=longlat +datum=WGS84 +no_defs 
## variables   : 3
## names       : comuna,         longitude,         latitude 
## min values  :      1, -76.5667986401345, 3.35072841959634 
## max values  :     22, -76.4709005858629,  3.4855565352251
plot(centroides)

plot(comunas)
points(centroides, col="red")

Atestiguamos que el centroide de la comuna 21 (la del extremo oriente) no está dentro de su polígono, esto sucede porque el centroide se calculó como el centro del semicírculo que forma la comuna, es debido a su forma particular de semicírculo. A esa comuna en específico le modificaremos la longitud de su centroide para que la coordenada cuadre dentro de la comuna/polígono:

centroid_coords_comunas[21,2] = -76.46452
centroid_coords_comunas[21,2]
## [1] -76.46452
centroid_coords_comunas
centroides2 = SpatialPointsDataFrame(coords = centroid_coords_comunas[,2:3],
                                    data = centroid_coords_comunas, proj4string = crs(comunas))

plot(comunas)
#points(centroides2[21,], col="red")

points(centroides2, col="red")

class(OrigenDestinoCali$comuna.origen)
## [1] "character"
class(centroid_coords_comunas$comuna)
## [1] "integer"

Ahora sí, según el anterior mapa, cada comuna tiene su centroide bien calculado y posicionado.

Convertimos las columnas de comunas origen-destino de nuestro dataset a entero dado que actualmente son de tipo “character”:

OrigenDestinoCali2 <- transform(OrigenDestinoCali,
                             comuna.origen = as.numeric(comuna.origen))
OrigenDestinoCali3 <- transform(OrigenDestinoCali2,
                                comuna.destino = as.numeric(comuna.destino))

OrigenDestinoCali3 <- transform(OrigenDestinoCali3,
                                comuna.origen = as.integer(comuna.origen))
OrigenDestinoCali3 <- transform(OrigenDestinoCali3,
                                comuna.destino = as.integer(comuna.destino))
class(OrigenDestinoCali2$comuna.origen)
## [1] "numeric"
class(OrigenDestinoCali3$comuna.destino)
## [1] "integer"

Uniremos el dataset OrigenDestinoCali3 con el dataset centroid_coords_comunas para precisamente ya tener todos los registros de origenes y destinos con coordenadas para hacer un análisis en el mapa geográfico. Para esto primero renombramos la columna “comuna” del dataset centroid_coords_comunas y le ponemos “comuna.origen” y despues “comuna.destino” para que se llamen igual en ambos dataset y poder hacer un Join/Merge.

colnames(centroid_coords_comunas) <- c("comuna.origen","longitud.origen","latitud.origen")
centroid_coords_comunas

Ahora lo unimos:

OrigenDestinoCali4 = merge(x = OrigenDestinoCali3, y = centroid_coords_comunas, by = "comuna.origen")

Volvemos a cambiar el nombre de las columnas para ponerles “columna.destino”, esta vez para unirlas por “comuna.destino”

colnames(centroid_coords_comunas) <- c("comuna.destino","longitud.destino","latitud.destino")
centroid_coords_comunas

Ahora lo unimos

OrigenDestinoCali5 = merge(x = OrigenDestinoCali4, y = centroid_coords_comunas, by = "comuna.destino")

Ahora que tenemos las coordenadas de cada origen y destino podemos establecer los gráficos:

Origenes = SpatialPointsDataFrame(coords = OrigenDestinoCali5[,29:30],
                                 data = OrigenDestinoCali5, proj4string = crs(comunas))

Destinos = SpatialPointsDataFrame(coords = OrigenDestinoCali5[,31:32],
                                  data = OrigenDestinoCali5, proj4string = crs(comunas))
Origenes[,1]
## class       : SpatialPointsDataFrame 
## features    : 22137 
## extent      : -76.5668, -76.46452, 3.350728, 3.485557  (xmin, xmax, ymin, ymax)
## crs         : +proj=longlat +datum=WGS84 +no_defs 
## variables   : 1
## names       : comuna.destino 
## min values  :              1 
## max values  :             22
comunas@data
origenes_porcomuna = over(comunas, Origenes[,1], fn = length)
destinos_porcomuna = over(comunas, Destinos[,1], fn = length)
comunas@data$origenes = origenes_porcomuna[,1]
comunas@data$destinos = destinos_porcomuna[,1]
comunas@data
comunas
## class       : SpatialPolygonsDataFrame 
## features    : 22 
## extent      : -76.59284, -76.46125, 3.331802, 3.505871  (xmin, xmax, ymin, ymax)
## crs         : +proj=longlat +datum=WGS84 +no_defs 
## variables   : 9
## names       : POLY_ID, casos, comuna,   nombre, zona_recol,         area, perimetro, origenes, destinos 
## min values  :       1,     1,      1, Comuna 1,         NA,  2329397.941,  7983.949,      257,      187 
## max values  :      22,    39,     22, Comuna 9,         NA, 12555929.024, 26480.361,     2249,     3771

Gráfico de todos los origenes por comuna (todos los vehiculos)

spplot(comunas[,8])

Gráfico de todos los destinos por comuna (todos los vehiculos)

spplot(comunas[,9])

Según la clasificación que tenemos en nuestro dataset la codificación de los tipos de vehículos son de esta manera:

1 - Bicicleta.

2 - Motocicleta.

3 - Automovil.

Ahora hacemos el proceso de origenes y destinos solamente para las bicicletas, como la codificación de bicicletas en nuestro dataset es “1”, filtramos por ese número en la variable “TIPO.DE.VEHÍCULO”:

OrigenDestinoCaliBicis=subset(OrigenDestinoCali5, OrigenDestinoCali5$TIPO.DE.VEHÍCULO=="1")
OrigenesBicis = SpatialPointsDataFrame(coords = OrigenDestinoCaliBicis[,29:30],
                                  data = OrigenDestinoCaliBicis, proj4string = crs(comunas))

DestinosBicis = SpatialPointsDataFrame(coords = OrigenDestinoCaliBicis[,31:32],
                                  data = OrigenDestinoCaliBicis, proj4string = crs(comunas))

origenesBicis_porcomuna = over(comunas, OrigenesBicis[,1], fn = length)
destinosBicis_porcomuna = over(comunas, DestinosBicis[,1], fn = length)
comunas@data$origenesBicis = origenesBicis_porcomuna[,1]
comunas@data$destinosBicis = destinosBicis_porcomuna[,1]

comunas@data

Gráfico de todos los origenes por comuna (solo bicicletas)

spplot(comunas[,10])

Gráfico de todos los destinos por comuna (solo bicicletas)

spplot(comunas[,11])

Ahora hacemos el proceso de origenes y destinos solamente para las motocicletas:

OrigenDestinoCaliMotos=subset(OrigenDestinoCali5, OrigenDestinoCali5$TIPO.DE.VEHÍCULO=="2")


OrigenesMotos = SpatialPointsDataFrame(coords = OrigenDestinoCaliMotos[,29:30],
                                       data = OrigenDestinoCaliMotos, proj4string = crs(comunas))

DestinosMotos = SpatialPointsDataFrame(coords = OrigenDestinoCaliMotos[,31:32],
                                       data = OrigenDestinoCaliMotos, proj4string = crs(comunas))

origenesMotos_porcomuna = over(comunas, OrigenesMotos[,1], fn = length)
destinosMotos_porcomuna = over(comunas, DestinosMotos[,1], fn = length)
comunas@data$origenesMotos = origenesMotos_porcomuna[,1]
comunas@data$destinosMotos = destinosMotos_porcomuna[,1]

comunas@data

Gráfico de todos los origenes por comuna (solo motocicletas)

spplot(comunas[,12])

Gráfico de todos los destinos por comuna (solo motocicletas)

spplot(comunas[,13])

Ahora hacemos el proceso de origenes y destinos solamente para las automoviles:

OrigenDestinoCaliAutos=subset(OrigenDestinoCali5, OrigenDestinoCali5$TIPO.DE.VEHÍCULO=="3")

OrigenesAutos = SpatialPointsDataFrame(coords = OrigenDestinoCaliAutos[,29:30],
                                       data = OrigenDestinoCaliAutos, proj4string = crs(comunas))

DestinosAutos = SpatialPointsDataFrame(coords = OrigenDestinoCaliAutos[,31:32],
                                       data = OrigenDestinoCaliAutos, proj4string = crs(comunas))

origenesAutos_porcomuna = over(comunas, OrigenesAutos[,1], fn = length)
destinosAutos_porcomuna = over(comunas, DestinosAutos[,1], fn = length)
comunas@data$origenesAutos = origenesAutos_porcomuna[,1]
comunas@data$destinosAutos = destinosAutos_porcomuna[,1]

comunas@data

Gráfico de todos los origenes por comuna (solo automoviles)

spplot(comunas[,14])

Gráfico de todos los destinos por comuna (solo automoviles)

spplot(comunas[,15])

CONCLUSIONES

  1. Vemos que en esta encuesta la comuna de donde sale más gente es la comuna 2 pero también es la comuna adonde va más gente.

  2. La comuna menos visitada siempre fue la comuna 12.

  3. El tipo de vehículo que más existe en el dataset es la motocicleta

  4. Según la encuesta el tipo de vehículo menos utilizado es la bicicleta