Este documento analiza la Encuesta Origen-Destino utilizando exclusivamente los desplazamientos realizados dentro de Santiago de Cali. El criterio de inclusión exige:
CALI.CALI.En el análisis se construyeron 8 mapas:
Los mapas utilizan la cartografía de comunas suministrada para el desarrollo de este ejercicio.
Interpretación importante: la concentración espacial observada es descriptiva y no demuestra por sí sola causalidad. Las explicaciones sobre rutas, ciclovías, trabajo, estudio, compras, etc. se plantean como hipótesis sustentadas en las variables disponibles y deben validarse con información adicional de infraestructura, empleo, educación, usos del suelo y red vial.
knitr::opts_chunk$set(
echo = TRUE,
message = FALSE,
warning = FALSE,
fig.align = "center",
out.width = "100%"
)
paquetes <- c(
"readxl", "dplyr", "tidyr", "stringr", "ggplot2",
"sf", "scales", "knitr", "purrr"
)
faltantes <- paquetes[!vapply(paquetes, requireNamespace, logical(1), quietly = TRUE)]
if (length(faltantes) > 0) {
install.packages(faltantes, repos = "https://cloud.r-project.org")
}
invisible(lapply(paquetes, library, character.only = TRUE))
options(scipen = 999)
La ruta del Excel puede modificarse mediante
ARCHIVO_EXCEL. La ruta de cartografía debe apuntar a la
carpeta que contiene los archivos geográficos de las comunas de
Cali.
ARCHIVO_EXCEL <- "C:/Users/dcruz/OneDrive - Consorcio Programa Servicios de Tránsito/Documentos/ElectivaUn1/EncuestaOrigenDestino.xlsx"
CARTO_PATH <- "C:/Users/dcruz/OneDrive - Consorcio Programa Servicios de Tránsito/Documentos/ElectivaUn1/cali"
if (!file.exists(ARCHIVO_EXCEL)) {
stop(
"No se encontró el archivo Excel. Revise ARCHIVO_EXCEL. ",
"Ruta actual: ", ARCHIVO_EXCEL
)
}
if (!dir.exists(CARTO_PATH)) {
stop(
"No se encontró la carpeta de cartografía. Revise CARTO_PATH. ",
"Ruta actual: ", CARTO_PATH
)
}
datos_raw <- readxl::read_excel(
ARCHIVO_EXCEL,
sheet = "Hoja1",
.name_repair = "unique"
)
convenciones <- readxl::read_excel(
ARCHIVO_EXCEL,
sheet = "Convenciones (2)",
.name_repair = "unique"
)
cat("Registros iniciales:", nrow(datos_raw), "\n")
## Registros iniciales: 35054
cat("Variables iniciales:", ncol(datos_raw), "\n")
## Variables iniciales: 28
limpiar_texto <- function(x) {
x |>
as.character() |>
stringr::str_squish() |>
stringr::str_to_upper()
}
limpiar_comuna <- function(x) {
z <- limpiar_texto(x)
z <- stringr::str_extract(z, "\\d+")
z <- stringr::str_pad(z, width = 2, side = "left", pad = "0")
z
}
# La hoja Hoja1 contiene DOS columnas con el mismo encabezado "MUNICIPIO":
# la primera corresponde al municipio de origen y la segunda al municipio de destino.
# readxl las renombra automáticamente (por ejemplo, MUNICIPIO...7 y MUNICIPIO...11).
# Por eso NO se debe referenciar MUNICIPIO directamente.
cols_municipio <- grep("^MUNICIPIO", names(datos_raw), ignore.case = TRUE)
if (length(cols_municipio) != 2) {
stop(
"Se esperaban exactamente dos columnas de municipio en Hoja1, " ,
"pero se encontraron ", length(cols_municipio), ". Revise los encabezados."
)
}
# Se valida que las columnas de comuna y vehículo existan antes de continuar.
columnas_requeridas <- c(
"comuna origen",
"comuna destino",
"TIPO DE VEHÍCULO",
"EDAD",
"SEXO",
"¿QUE VA HACER A ESE LUGAR?"
)
faltantes <- setdiff(columnas_requeridas, names(datos_raw))
if (length(faltantes) > 0) {
stop(
"Faltan columnas requeridas en Hoja1: ",
paste(faltantes, collapse = ", ")
)
}
# Uso de .data[[...]] para que el código funcione tanto con MUNICIPIO...7/
# MUNICIPIO...11 como con cualquier otro nombre que genere readxl.
datos <- datos_raw |>
mutate(
municipio_origen = limpiar_texto(.data[[names(datos_raw)[cols_municipio[1]]]]),
municipio_destino = limpiar_texto(.data[[names(datos_raw)[cols_municipio[2]]]]),
comuna_origen = limpiar_comuna(.data[["comuna origen"]]),
comuna_destino = limpiar_comuna(.data[["comuna destino"]]),
vehiculo_codigo = suppressWarnings(as.numeric(.data[["TIPO DE VEHÍCULO"]])),
edad_num = suppressWarnings(as.numeric(.data[["EDAD"]])),
sexo_codigo = suppressWarnings(as.numeric(.data[["SEXO"]])),
proposito_destino = suppressWarnings(
as.numeric(.data[["¿QUE VA HACER A ESE LUGAR?"]])
)
)
comunas_validas <- sprintf("%02d", 1:22)
datos_cali <- datos |>
filter(
municipio_origen == "CALI",
municipio_destino == "CALI",
comuna_origen %in% comunas_validas,
comuna_destino %in% comunas_validas
) |>
mutate(
vehiculo = case_when(
vehiculo_codigo == 1 ~ "Bicicleta",
vehiculo_codigo == 2 ~ "Motocicleta",
vehiculo_codigo == 3 ~ "Automóvil",
TRUE ~ NA_character_
),
proposito_destino_label = case_when(
proposito_destino == 1 ~ "A trabajar",
proposito_destino == 2 ~ "Asuntos de trabajo",
proposito_destino == 3 ~ "Estudiar",
proposito_destino == 4 ~ "Atención de salud",
proposito_destino == 5 ~ "Ver a alguien",
proposito_destino == 6 ~ "Volver a casa",
proposito_destino == 7 ~ "Buscar/dejar a alguien",
proposito_destino == 8 ~ "Buscar/dejar algo",
proposito_destino == 9 ~ "Comer/tomar algo",
proposito_destino == 10 ~ "Compras",
proposito_destino == 11 ~ "Trámites",
proposito_destino == 12 ~ "Recreación",
proposito_destino == 13 ~ "Buscar trabajo",
proposito_destino == 77 ~ "Otra cosa",
TRUE ~ "Sin información"
)
)
cat("Registros después del filtro Cali-Cali y comunas 01-22:", nrow(datos_cali), "\n")
## Registros después del filtro Cali-Cali y comunas 01-22: 22139
El control de calidad se realiza en cuatro dimensiones:
completitud <- datos |>
summarise(across(everything(), ~ mean(!is.na(.)))) |>
pivot_longer(
cols = everything(),
names_to = "variable",
values_to = "completitud"
) |>
mutate(
porcentaje_completitud = completitud * 100
) |>
arrange(completitud)
ggplot(
completitud |> slice_head(n = 15),
aes(
x = reorder(variable, porcentaje_completitud),
y = porcentaje_completitud
)
) +
geom_col(fill = "#F6B6C8", color = "#8E6C78") +
coord_flip() +
scale_y_continuous(
limits = c(0, 100),
labels = scales::label_percent(scale = 1)
) +
labs(
title = "Control de completitud: variables con menor \n porcentaje de información",
x = NULL,
y = "Completitud (%)"
) +
theme_minimal(base_size = 12)+
theme(
plot.title = element_text(hjust = 0.5)
)
Interpretación. Las variables abiertas y de observaciones pueden presentar una alta proporción de valores vacíos sin que esto represente necesariamente un error: en varios casos corresponden a preguntas condicionales. Para los mapas se priorizan municipio, comuna y tipo de vehículo.
duplicados <- sum(duplicated(datos))
tabla_duplicados <- tibble(
Estado = c("Registros únicos", "Registros duplicados"),
Registros = c(nrow(datos) - duplicados, duplicados)
)
ggplot(
tabla_duplicados,
aes(x = Estado, y = Registros, fill = Estado)
) +
geom_col(width = 0.65, color = "#7D6570") +
scale_fill_manual(values = c(
"Registros únicos" = "#B8E0D2",
"Registros duplicados" = "#F6B6C8"
)) +
labs(
title = "Control de duplicidad",
x = NULL,
y = "Número de registros"
) +
theme_minimal(base_size = 12) +
theme(legend.position = "none")
cat("Registros iniciales:", nrow(datos), "\n")
## Registros iniciales: 35054
cat("Duplicados exactos:", duplicados, "\n")
## Duplicados exactos: 1
cat("Registros Cali-Cali con comunas 01-22:", nrow(datos_cali), "\n")
## Registros Cali-Cali con comunas 01-22: 22139
cat(
"Registros Cali-Cali antes de validar comunas:",
sum(datos$municipio_origen == "CALI" & datos$municipio_destino == "CALI", na.rm = TRUE),
"\n"
)
## Registros Cali-Cali antes de validar comunas: 24528
calidad_comunas <- tibble(
Indicador = c(
"Origen válido 01-22",
"Destino válido 01-22",
"Origen fuera de rango/no informado",
"Destino fuera de rango/no informado"
),
Registros = c(
sum(datos$comuna_origen %in% comunas_validas, na.rm = TRUE),
sum(datos$comuna_destino %in% comunas_validas, na.rm = TRUE),
sum(!datos$comuna_origen %in% comunas_validas | is.na(datos$comuna_origen)),
sum(!datos$comuna_destino %in% comunas_validas | is.na(datos$comuna_destino))
)
)
ggplot(
calidad_comunas,
aes(x = reorder(Indicador, Registros), y = Registros, fill = Indicador)
) +
geom_col(color = "#7D6570") +
coord_flip() +
scale_fill_brewer(palette = "Pastel1") +
labs(
title = "Calidad de los códigos de comuna",
x = NULL,
y = "Registros"
) +
theme_minimal(base_size = 12) +
theme(legend.position = "none")
vehiculos_qc <- datos_cali |>
count(vehiculo, name = "registros") |>
mutate(
vehiculo = replace_na(vehiculo, "Sin información")
)
ggplot(
vehiculos_qc,
aes(x = reorder(vehiculo, registros), y = registros, fill = vehiculo)
) +
geom_col(color = "#7D6570") +
coord_flip() +
scale_fill_brewer(palette = "Pastel1") +
labs(
title = "Distribución del tipo de vehículo en la muestra Cali-Cali",
x = NULL,
y = "Registros"
) +
theme_minimal(base_size = 12) +
theme(legend.position = "none")
La base contiene registros de viajes internos y externos. Para responder específicamente la pregunta sobre los desplazamientos dentro de Cali, el análisis elimina los registros cuyo municipio de origen o destino no corresponde a Cali y conserva solamente las comunas 01 a 22.
Además, se mantienen separados los registros sin tipo de vehículo de los tres modos solicitados. Por esta razón, los mapas específicos por modo utilizan únicamente:
Esto evita asignar artificialmente un modo de transporte a observaciones sin información.
El código siguiente busca automáticamente archivos geográficos dentro
de CARTO_PATH. Se admiten Shapefile, GeoPackage, GeoJSON y
otros formatos soportados por sf.
archivos_geo <- list.files(
CARTO_PATH,
pattern = "\\.(shp|gpkg|geojson|json|kml)$",
recursive = TRUE,
full.names = TRUE,
ignore.case = TRUE
)
if (length(archivos_geo) == 0) {
stop(
"No se encontraron archivos geográficos en CARTO_PATH. ",
"La carpeta debe contener la cartografía de las comunas de Cali."
)
}
# Se intenta priorizar nombres relacionados con comunas.
prioridad <- grepl(
"comun|cali|localidad|zona",
basename(archivos_geo),
ignore.case = TRUE
)
archivo_carto <- if (any(prioridad)) {
archivos_geo[which(prioridad)[1]]
} else {
archivos_geo[1]
}
cat("Archivo cartográfico seleccionado:", archivo_carto, "\n")
## Archivo cartográfico seleccionado: C:/Users/dcruz/OneDrive - Consorcio Programa Servicios de Tránsito/Documentos/ElectivaUn1/cali/Comunas.shp
mapa <- sf::st_read(
archivo_carto,
quiet = TRUE,
stringsAsFactors = FALSE
)
mapa <- sf::st_make_valid(mapa)
# Unificación del sistema de referencia.
if (is.na(sf::st_crs(mapa))) {
warning(
"La cartografía no tiene CRS definido. Se conserva tal como fue entregada."
)
}
names(mapa)
## [1] "OBJECTID" "gid" "comuna" "nombre" "geometry"
nombres_mapa <- names(mapa)
candidatos_comuna <- nombres_mapa[
grepl(
"comun|cod.*com|com.*cod|codigo|código|zona",
nombres_mapa,
ignore.case = TRUE
)
]
if (length(candidatos_comuna) == 0) {
stop(
"No fue posible identificar automáticamente el campo de comuna en la cartografía. ",
"Revise names(mapa) y asigne manualmente el campo."
)
}
campo_comuna <- candidatos_comuna[1]
cat("Campo de comuna seleccionado:", campo_comuna, "\n")
## Campo de comuna seleccionado: comuna
mapa <- mapa |>
mutate(
comuna_mapa_raw = .data[[campo_comuna]],
comuna_mapa = limpiar_comuna(comuna_mapa_raw)
) |>
filter(comuna_mapa %in% comunas_validas)
if (nrow(mapa) < 22) {
warning(
"La cartografía contiene menos de 22 polígonos después del filtro. ",
"Revise el campo seleccionado: ", campo_comuna
)
}
# Si hay múltiples geometrías por comuna, se disuelven.
mapa <- mapa |>
group_by(comuna_mapa) |>
summarise(geometry = sf::st_union(geometry), .groups = "drop")
origen_total <- datos_cali |>
count(comuna_origen, name = "viajes")
destino_total <- datos_cali |>
count(comuna_destino, name = "viajes")
origen_modo <- datos_cali |>
filter(vehiculo %in% c("Bicicleta", "Motocicleta", "Automóvil")) |>
count(vehiculo, comuna_origen, name = "viajes")
destino_modo <- datos_cali |>
filter(vehiculo %in% c("Bicicleta", "Motocicleta", "Automóvil")) |>
count(vehiculo, comuna_destino, name = "viajes")
mapear_comuna <- function(mapa, tabla, campo_tabla) {
mapa |>
left_join(
tabla,
by = setNames(campo_tabla, "comuna_mapa")
) |>
mutate(viajes = replace_na(viajes, 0))
}
mapa_coropletico <- function(mapa_df, titulo, subtitulo = NULL) {
ggplot() +
geom_sf(
data = mapa_df,
aes(fill = viajes),
color = "white",
linewidth = 0.35
) +
geom_sf_text(
data = mapa_df,
aes(label = comuna_mapa),
size = 3,
color = "grey20",
fontface = "bold"
) +
scale_fill_gradient(
low = "#FCE4EC",
high = "#AD1457",
labels = scales::label_comma(),
name = "Viajes"
) +
labs(
title = titulo,
subtitle = subtitulo,
caption = "Fuente: Encuesta Origen-Destino. Elaboración propia."
) +
theme_void(base_size = 12) +
theme(
plot.title = element_text(face = "bold", size = 16),
plot.subtitle = element_text(size = 11),
plot.caption = element_text(size = 9),
legend.position = "right"
)
}
mapa_origen_total <- mapear_comuna(
mapa,
origen_total,
"comuna_origen"
)
mapa_coropletico(
mapa_origen_total,
"Mapa 1. Concentración de los orígenes de los viajes",
"Viajes internos Cali-Cali, todas las modalidades"
)
Interpretación. Las comunas con mayor intensidad representan los lugares donde se concentra una mayor cantidad de viajes que posteriormente se dirigen hacia otros puntos de Cali. El mapa debe interpretarse como una distribución de observaciones de la encuesta, no como una estimación directa de toda la población de Cali.
mapa_origen_bici <- mapa |>
left_join(
origen_modo |> filter(vehiculo == "Bicicleta"),
by = c("comuna_mapa" = "comuna_origen")
) |>
mutate(viajes = replace_na(viajes, 0))
mapa_coropletico(
mapa_origen_bici,
"Mapa 2. Orígenes de viajes en bicicleta",
"Modo: bicicleta"
)
mapa_origen_moto <- mapa |>
left_join(
origen_modo |> filter(vehiculo == "Motocicleta"),
by = c("comuna_mapa" = "comuna_origen")
) |>
mutate(viajes = replace_na(viajes, 0))
mapa_coropletico(
mapa_origen_moto,
"Mapa 3. Orígenes de viajes en motocicleta",
"Modo: motocicleta"
)
mapa_origen_auto <- mapa |>
left_join(
origen_modo |> filter(vehiculo == "Automóvil"),
by = c("comuna_mapa" = "comuna_origen")
) |>
mutate(viajes = replace_na(viajes, 0))
mapa_coropletico(
mapa_origen_auto,
"Mapa 4. Orígenes de viajes en automóvil",
"Modo: automóvil"
)
mapa_destino_total <- mapa |>
left_join(
destino_total,
by = c("comuna_mapa" = "comuna_destino")
) |>
mutate(viajes = replace_na(viajes, 0))
mapa_coropletico(
mapa_destino_total,
"Mapa 5. Concentración de los destinos de los viajes",
"Viajes internos Cali-Cali, todas las modalidades"
)
Interpretación. Las comunas con mayor intensidad concentran los puntos de llegada declarados por las personas encuestadas. La diferencia entre el mapa de origen y el de destino permite identificar áreas que funcionan relativamente más como generadoras o atractoras de viajes.
mapa_destino_bici <- mapa |>
left_join(
destino_modo |> filter(vehiculo == "Bicicleta"),
by = c("comuna_mapa" = "comuna_destino")
) |>
mutate(viajes = replace_na(viajes, 0))
mapa_coropletico(
mapa_destino_bici,
"Mapa 6. Destinos de viajes en bicicleta",
"Modo: bicicleta"
)
mapa_destino_moto <- mapa |>
left_join(
destino_modo |> filter(vehiculo == "Motocicleta"),
by = c("comuna_mapa" = "comuna_destino")
) |>
mutate(viajes = replace_na(viajes, 0))
mapa_coropletico(
mapa_destino_moto,
"Mapa 7. Destinos de viajes en motocicleta",
"Modo: motocicleta"
)
mapa_destino_auto <- mapa |>
left_join(
destino_modo |> filter(vehiculo == "Automóvil"),
by = c("comuna_mapa" = "comuna_destino")
) |>
mutate(viajes = replace_na(viajes, 0))
mapa_coropletico(
mapa_destino_auto,
"Mapa 8. Destinos de viajes en automóvil",
"Modo: automóvil"
)
El análisis espacial permite identificar patrones de atracción, pero la explicación debe apoyarse en las respuestas de propósito del viaje. Para evitar una interpretación causal no sustentada, se calcula primero la distribución de las actividades declaradas en el destino.
propositos <- datos_cali |>
filter(vehiculo %in% c("Bicicleta", "Motocicleta", "Automóvil")) |>
count(vehiculo, proposito_destino_label, name = "viajes") |>
group_by(vehiculo) |>
mutate(
porcentaje = viajes / sum(viajes) * 100
) |>
ungroup() |>
arrange(vehiculo, desc(viajes))
knitr::kable(
propositos |>
group_by(vehiculo) |>
slice_head(n = 8) |>
select(vehiculo, proposito_destino_label, viajes, porcentaje),
digits = 1,
col.names = c("Vehículo", "Actividad en destino", "Viajes", "%")
)
| Vehículo | Actividad en destino | Viajes | % |
|---|---|---|---|
| Automóvil | A trabajar | 3630 | 42.2 |
| Automóvil | Asuntos de trabajo | 1282 | 14.9 |
| Automóvil | Volver a casa | 1200 | 14.0 |
| Automóvil | Trámites | 539 | 6.3 |
| Automóvil | Buscar/dejar a alguien | 413 | 4.8 |
| Automóvil | Compras | 328 | 3.8 |
| Automóvil | Ver a alguien | 289 | 3.4 |
| Automóvil | Atención de salud | 267 | 3.1 |
| Bicicleta | A trabajar | 679 | 55.5 |
| Bicicleta | Volver a casa | 175 | 14.3 |
| Bicicleta | Asuntos de trabajo | 125 | 10.2 |
| Bicicleta | Trámites | 52 | 4.3 |
| Bicicleta | Compras | 30 | 2.5 |
| Bicicleta | Buscar/dejar a alguien | 27 | 2.2 |
| Bicicleta | Estudiar | 26 | 2.1 |
| Bicicleta | Ver a alguien | 26 | 2.1 |
| Motocicleta | A trabajar | 5251 | 51.0 |
| Motocicleta | Asuntos de trabajo | 1715 | 16.6 |
| Motocicleta | Volver a casa | 1359 | 13.2 |
| Motocicleta | Trámites | 464 | 4.5 |
| Motocicleta | Estudiar | 258 | 2.5 |
| Motocicleta | Buscar/dejar a alguien | 246 | 2.4 |
| Motocicleta | Compras | 240 | 2.3 |
| Motocicleta | Atención de salud | 206 | 2.0 |
top_propositos <- propositos |>
group_by(vehiculo) |>
slice_max(viajes, n = 3, with_ties = FALSE) |>
summarise(
principales = paste0(
proposito_destino_label,
" (", round(porcentaje, 1), "%)",
collapse = "; "
),
.groups = "drop"
)
knitr::kable(
top_propositos,
col.names = c("Vehículo", "Tres principales propósitos")
)
| Vehículo | Tres principales propósitos |
|---|---|
| Automóvil | A trabajar (42.2%); Asuntos de trabajo (14.9%); Volver a casa (14%) |
| Bicicleta | A trabajar (55.5%); Volver a casa (14.3%); Asuntos de trabajo (10.2%) |
| Motocicleta | A trabajar (51%); Asuntos de trabajo (16.6%); Volver a casa (13.2%) |
Cuando el mapa de bicicleta muestre concentración en determinadas comunas, una explicación plausible es la proximidad entre vivienda y actividades cotidianas, especialmente trabajo, regreso a casa, estudio, compras o trámites. La existencia de infraestructura ciclista puede favorecer la elección de determinados corredores, pero la base de la encuesta no permite afirmar que una concentración se deba exclusivamente a las ciclovías.
Para comprobar esta hipótesis se recomienda cruzar posteriormente los viajes con la red de ciclovías, estaciones de bicicleta pública, pendientes, seguridad vial y distancia del viaje.
La motocicleta puede presentar una distribución territorial amplia porque permite realizar viajes relativamente directos y flexibles entre zonas residenciales y zonas de empleo. Si las principales razones de destino corresponden a trabajo, asuntos laborales y regreso a casa, el patrón es compatible con desplazamientos cotidianos de carácter laboral.
La interpretación debe complementarse con distancia recorrida, tiempos de viaje, congestión, disponibilidad de estacionamiento y costos relativos frente al automóvil y al transporte público.
La concentración de destinos en determinadas comunas puede estar relacionada con centralidades urbanas, concentración de actividades económicas, servicios, comercio, educación, salud y otros equipamientos. Si predominan trabajo, asuntos de trabajo, regreso a casa, trámites y compras, existe evidencia descriptiva de que las actividades urbanas tienen un papel importante en la atracción de viajes.
No obstante, con esta encuesta no es posible establecer que una determinada actividad sea la causa única de la concentración espacial.
Además de los ocho mapas, se construye una matriz para identificar los pares origen-destino con mayor frecuencia.
matriz_od <- datos_cali |>
filter(vehiculo %in% c("Bicicleta", "Motocicleta", "Automóvil")) |>
count(vehiculo, comuna_origen, comuna_destino, name = "viajes") |>
arrange(vehiculo, desc(viajes))
knitr::kable(
matriz_od |>
group_by(vehiculo) |>
slice_head(n = 10) |>
select(vehiculo, comuna_origen, comuna_destino, viajes),
col.names = c("Vehículo", "Origen", "Destino", "Viajes")
)
| Vehículo | Origen | Destino | Viajes |
|---|---|---|---|
| Automóvil | 19 | 02 | 215 |
| Automóvil | 02 | 02 | 189 |
| Automóvil | 17 | 02 | 128 |
| Automóvil | 17 | 22 | 116 |
| Automóvil | 02 | 19 | 106 |
| Automóvil | 19 | 19 | 101 |
| Automóvil | 03 | 02 | 96 |
| Automóvil | 02 | 03 | 93 |
| Automóvil | 03 | 19 | 90 |
| Automóvil | 18 | 02 | 90 |
| Bicicleta | 02 | 02 | 24 |
| Bicicleta | 19 | 02 | 22 |
| Bicicleta | 02 | 03 | 21 |
| Bicicleta | 18 | 03 | 21 |
| Bicicleta | 18 | 02 | 20 |
| Bicicleta | 02 | 19 | 17 |
| Bicicleta | 17 | 02 | 17 |
| Bicicleta | 17 | 22 | 17 |
| Bicicleta | 03 | 02 | 15 |
| Bicicleta | 18 | 19 | 15 |
| Motocicleta | 02 | 02 | 233 |
| Motocicleta | 19 | 02 | 212 |
| Motocicleta | 17 | 02 | 166 |
| Motocicleta | 02 | 19 | 155 |
| Motocicleta | 17 | 22 | 140 |
| Motocicleta | 18 | 02 | 131 |
| Motocicleta | 17 | 03 | 116 |
| Motocicleta | 02 | 03 | 115 |
| Motocicleta | 03 | 02 | 110 |
| Motocicleta | 19 | 19 | 109 |
generadoras <- datos_cali |>
count(comuna_origen, name = "origenes")
atractoras <- datos_cali |>
count(comuna_destino, name = "destinos")
comparacion_comunas <- tibble(
comuna = comunas_validas
) |>
left_join(
generadoras,
by = c("comuna" = "comuna_origen")
) |>
left_join(
atractoras,
by = c("comuna" = "comuna_destino")
) |>
mutate(
origenes = replace_na(origenes, 0),
destinos = replace_na(destinos, 0),
balance = destinos - origenes
) |>
arrange(desc(balance))
knitr::kable(
comparacion_comunas,
col.names = c("Comuna", "Orígenes", "Destinos", "Balance destino-origen")
)
| Comuna | Orígenes | Destinos | Balance destino-origen |
|---|---|---|---|
| 02 | 2249 | 3772 | 1523 |
| 03 | 1608 | 2881 | 1273 |
| 22 | 979 | 1561 | 582 |
| 09 | 737 | 1055 | 318 |
| 04 | 1193 | 1496 | 303 |
| 19 | 2240 | 2438 | 198 |
| 07 | 583 | 598 | 15 |
| 08 | 862 | 830 | -32 |
| 12 | 257 | 207 | -50 |
| 05 | 521 | 440 | -81 |
| 17 | 1762 | 1615 | -147 |
| 16 | 836 | 645 | -191 |
| 06 | 796 | 570 | -226 |
| 11 | 717 | 483 | -234 |
| 14 | 574 | 316 | -258 |
| 21 | 693 | 434 | -259 |
| 20 | 599 | 303 | -296 |
| 10 | 1094 | 741 | -353 |
| 01 | 626 | 187 | -439 |
| 13 | 1031 | 560 | -471 |
| 15 | 974 | 481 | -493 |
| 18 | 1208 | 526 | -682 |
El indicador balance = destinos - orígenes es
descriptivo:
No debe interpretarse como un balance poblacional completo de la comuna, porque la encuesta es una muestra y su diseño de interceptación puede generar diferentes probabilidades de observación.
resumen_modo <- datos_cali |>
count(vehiculo, name = "viajes") |>
mutate(
porcentaje = viajes / sum(viajes) * 100
) |>
arrange(desc(viajes))
knitr::kable(
resumen_modo,
digits = 1,
col.names = c("Modo", "Viajes", "%")
)
| Modo | Viajes | % |
|---|---|---|
| Motocicleta | 10302 | 46.5 |
| Automóvil | 8598 | 38.8 |
| NA | 2016 | 9.1 |
| Bicicleta | 1223 | 5.5 |
A partir de los mapas y tablas deben destacarse tres aspectos:
El documento lo diseñe para ejecutarse en RStudio y permite modificar únicamente las rutas de entrada:
ARCHIVO_EXCEL <- "C:/ruta/EncuestaOrigenDestino.xlsx"
CARTO_PATH <- "C:/ruta/cali"
El resto del flujo lo realiza automáticamente:
Hoja1;Esto se hace con el objeto de verificar la validez de los hallazgos y generar confianza en los resultados.
Nota para la cartografía: como la carpeta
calicontiene varios archivos geográficos, éste código prioriza archivos cuyo nombre contiene términos comocomun,cali,localidadozona. Si existen varias capas posibles, se reviso y valido que en la salida denames(mapa)el campo identificado comocampo_comunasea efectivamente el número de comuna.