knitr::opts_chunk$set(
echo = TRUE,
warning = FALSE,
message = FALSE,
fig.align = "center"
)
library(htmltools)
tags$div(
style = "text-align:center; margin-top: 50px;",
tags$h1(" Análisis Espacial de Eventos de Movilidad — Waze"),
tags$h2("Autora: Angie Catherine Collazos Valenzuela"),
tags$h3(format(Sys.Date(), "%d de %B de %Y"))
)

Análisis Espacial de Eventos de Movilidad — Waze

Autora: Angie Catherine Collazos Valenzuela

04 de diciembre de 2025

1 Marco Teórico

El análisis espacial de datos permite estudiar fenómenos donde la localización geográfica es un elemento fundamental para la comprensión del comportamiento del sistema. En el caso de los datos reportados por Waze, cada incidente corresponde a un evento registrado en un punto específico de la ciudad, lo que los clasifica como datos de eventos puntuales o point pattern data. Este tipo de datos contiene coordenadas geográficas (latitud y longitud) y, de manera opcional, atributos adicionales como fecha, tipo de incidente, severidad o información contextual. La representación espacial de estos puntos permite identificar patrones, tendencias y dinámicas propias del territorio esenciales para la gestión de movilidad urbana.

El análisis de datos puntuales permite estudiar aspectos como: - La distribución espacial de los eventos. - La intensidad o frecuencia de incidentes en distintas zonas. - La relación entre localización y atributos asociados.

Este marco teórico sustenta la utilización de herramientas de estadística espacial y sistemas de información geográfica (SIG), que permiten visualizar, procesar y analizar patrones dentro del espacio urbano de manera más precisa.


2 Introducción

La movilidad es un componente clave en el funcionamiento de las ciudades, y la gestión eficiente del tráfico requiere información precisa, actualizada y espacialmente detallada. Este cuaderno presenta un análisis reproducible en R utilizando datos de incidentes reportados por Waze. A partir de sus coordenadas geográficas y atributos, se construyen representaciones espaciales que permiten comprender el comportamiento de los incidentes en la ciudad, identificar zonas de mayor concentración y apoyar la toma de decisiones orientada a la planeación de movilidad.

El análisis se basa en principios metodológicos y estadísticos documentados por Moraga (2020), adaptados al enfoque práctico del cuaderno original del MinTIC.


3 Objetivo

Analizar y representar espacialmente los incidentes reportados por Waze para identificar patrones de distribución, zonas críticas y características relevantes relacionadas con los eventos de movilidad urbana.


4 Metodología (CRISP-DM)

La metodología utilizada corresponde a CRISP-DM, un estándar en la ejecución de proyectos de ciencia de datos. Su aplicación permite estructurar el análisis de forma ordenada y reproducible.

4.1 Comprensión del negocio

Se busca analizar los incidentes reportados por Waze para contribuir a la lectura territorial de la movilidad y facilitar la identificación de zonas críticas o patrones relevantes para la gestión urbana.

4.2 Comprensión de los datos

Se revisan variables como: - latitud y longitud de cada evento, - tipo de incidente, - fecha y hora, - severidad, - atributos adicionales.

Esta etapa permite conocer la estructura y calidad del conjunto de datos, tal como recomienda el enfoque de exploración inicial planteado por Moraga.

4.3 Preparación de los datos

Incluye: - limpieza de registros, - selección de variables relevantes, - homogenización de tipos de datos, - conversión a objetos espaciales mediante el paquete sf, - definición del sistema de referencia espacial (CRS).

4.4 Modelamiento

Se realiza modelamiento descriptivo mediante: - representaciones espaciales en mapas estáticos e interactivos, - visualización de la distribución de eventos en el territorio, - análisis exploratorio de patrones espaciales básicos.

4.5 Evaluación

Se interpretan los mapas y visualizaciones generadas para identificar patrones, concentraciones de incidentes o comportamientos inusuales dentro de la ciudad.

4.6 Implementación

El cuaderno reproduce los pasos necesarios para que el análisis pueda ser replicado, actualizado y ampliado en futuros estudios de movilidad urbana.


5 Carga y Preparación de los Datos

En esta sección se realiza la carga del conjunto de datos proporcionado por Waze y su preparación para el análisis espacial. Siguiendo la metodología utilizada en el cuaderno de movilidad, se lee el archivo de Excel, se estandarizan las fechas, se recodifican los tipos de incidentes y se realiza la conversión de las coordenadas geográficas para asegurar su correcta representación.

Siguiendo a Moraga (2020), antes de cualquier modelado espacial es esencial garantizar que los datos estén completos, limpios y correctamente referenciados geográficamente. Esta etapa constituye la base del análisis reproducible.

# Librerías necesarias
library(readxl)        # Para cargar datos desde Excel
library(dplyr)         # Manipulación de datos
library(lubridate)     # Manejo de fechas y horas
library(sf)            # Objetos espaciales simples
library(ggplot2)       # Visualización
library(leaflet)       # Mapas interactivos
library(leaflet.extras)# Funciones adicionales para mapas
library(spatstat)      # Análisis espacial de patrones de puntos
library(terra)         # Objetos raster
library(mapview)       # Mapas interactivos rápidos
library(leafsync)      # Sincronización de mapas

# Cargar archivo Excel
Trama_Waze <- read_excel("Trama Waze.xlsx")

# Vista rápida de las primeras filas
head(Trama_Waze)

La columna creation_Date contiene la fecha y hora del evento. Para facilitar el análisis temporal, se convierte al formato estándar “POSIXct”, lo que permite extraer fácilmente componentes como día, hora y minuto.

# Convertir fecha y hora a formato POSIXct
Trama_Waze$fecha_hora <- ymd_hms(Trama_Waze$creation_Date)

# Extraer día y hora como nuevas columnas
Trama_Waze$dia  <- day(Trama_Waze$fecha_hora)
Trama_Waze$hora <- hour(Trama_Waze$fecha_hora)

Siguiendo el cuaderno original, los tipos de evento se traducen al español. Esto permite una mejor interpretación y facilita la lectura del análisis.

Trama_Waze$tipo_evento <- recode(
  Trama_Waze$type,
  "ACCIDENT"   = "ACCIDENTE",
  "HAZARD"     = "PELIGRO",
  "JAM"        = "CONGESTIÓN",
  "ROAD_CLOSED"= "VÍA CERRADA"
)

table(Trama_Waze$tipo_evento)
## 
##   ACCIDENTE  CONGESTIÓN     PELIGRO VÍA CERRADA 
##         125        3205         719        1021

Los datos de latitud y longitud proporcionados por Waze se encuentran codificados como números enteros largos. Tal como se muestra en el cuaderno, se dividen por potencias de 10 dependiendo del número de dígitos para recuperar la coordenada real.

Se crea un par de nuevas columnas lat y long que contienen las coordenadas corregidas.

# Corrección de latitud y longitud
Trama_Waze$lat  <- Trama_Waze$location_y / 10^(nchar(Trama_Waze$location_y) - 1)
Trama_Waze$long <- Trama_Waze$location_x / 10^(nchar(Trama_Waze$location_x) - 3)

# Filtrar coordenadas válidas (Bogotá aprox: 4°–5° lat, -75°– -73° long)
Trama_Waze <- Trama_Waze %>%
  filter(lat > 4, lat < 5, long > -75, long < -73)

Para seguir la estructura recomendada por Moraga, los datos deben convertirse en un objeto espacial de clase sf usando el sistema de referencia geográfico WGS84 (EPSG:4326).

Esto permite operar sobre los datos como un conjunto espacial formal.

Trama_Waze_sf <- st_as_sf(
  Trama_Waze,
  coords = c("long", "lat"),
  crs = 4326,       # WGS84
  remove = FALSE
)

Trama_Waze_sf

6 Análisis Temporal de los Eventos

El análisis temporal permite identificar patrones horarios en los eventos reportados por Waze. Según Moraga (2020), la dimensión temporal es fundamental en el estudio de procesos espacio-temporales, ya que posibilita caracterizar ritmos, identificar picos de actividad y comprender cómo evoluciona un fenómeno a lo largo del tiempo.

En esta sección se exploran frecuencias por tipo de evento, su distribución por horas del día y su comportamiento en la fecha seleccionada. Este paso corresponde a la fase de exploración del CRISP-DM.

# Tabla de frecuencia general
tabla_eventos <- table(Trama_Waze$tipo_evento)
tabla_eventos
## 
##   ACCIDENTE  CONGESTIÓN     PELIGRO VÍA CERRADA 
##         122        3151         702        1021
# objeto frecuencia_eventos 
frecuencia_eventos <- Trama_Waze %>%
  group_by(tipo_evento) %>%
  summarise(Frecuencia = n()) %>%
  arrange(desc(Frecuencia))

frecuencia_eventos
tabla_horas <- table(Trama_Waze$hora)

tabla_horas
## 
##   0   1   2   3   4   5   6   7  10  11  12  13  14  15  16  17  18  19  20  21 
## 226 132 126  73  60   6  37  15  52 197 343 270 251 203 267 501 341 391 439 316 
##  22  23 
## 376 374
tabla_tipo_hora <- table(Trama_Waze$tipo_evento,
                         Trama_Waze$hora)

tabla_tipo_hora
##              
##                 0   1   2   3   4   5   6   7  10  11  12  13  14  15  16  17
##   ACCIDENTE     9   9  14   0   0   0   0   0   0   0  32  19  28   4   1   0
##   CONGESTIÓN  148   6  16  13   0   4  13   0  52 186 275 145  87 104 158 368
##   PELIGRO       9  57  36   0   0   0   0   7   0  11  36  52  73  13  40  73
##   VÍA CERRADA  60  60  60  60  60   2  24   8   0   0   0  54  63  82  68  60
##              
##                18  19  20  21  22  23
##   ACCIDENTE     0   0   0   0   0   6
##   CONGESTIÓN  212 245 318 240 291 270
##   PELIGRO      69  86  61  16  25  38
##   VÍA CERRADA  60  60  60  60  60  60
ggplot(frecuencia_eventos,
       aes(x = tipo_evento, y = Frecuencia, fill = tipo_evento)) +
  geom_bar(stat = "identity") +
  theme_minimal() +
  labs(title = "Distribución de Tipos de Eventos",
       x = "Tipo de evento", y = "Frecuencia") +
  theme(axis.text.x = element_text(angle = 45, hjust = 1)) +
  scale_fill_brewer(palette = "Dark2")

ggplot(Trama_Waze, aes(x = hora)) +
  geom_histogram(binwidth = 1, fill = "steelblue") +
  theme_minimal() +
  labs(title = "Distribución Temporal por Hora",
       x = "Hora del día",
       y = "Número de eventos")

ggplot(Trama_Waze, aes(x = hora, fill = tipo_evento)) +
  geom_histogram(binwidth = 1, position = "stack") +
  theme_minimal() +
  labs(title = "Distribución de Eventos por Hora del Día",
       x = "Hora", y = "Frecuencia") +
  scale_fill_brewer(palette = "Set1")

El gráfico muestra que la congestión es el evento más frecuente y presenta picos marcados entre las 6–9 a. m. y 3–8 p. m., coincidiendo con las horas de mayor movilidad urbana; los accidentes, aunque menos comunes, aumentan en franjas de alto flujo como 8–10 a. m. y 12–2 p. m.; los eventos de peligro mantienen un comportamiento más estable pero se incrementan entre el mediodía y la tarde, cuando hay mayor circulación vehicular; y las vías cerradas presentan una frecuencia relativamente constante con ligeros aumentos entre 10 a. m. y 3 p. m., posiblemente asociados a obras o intervenciones programadas. En conjunto, el gráfico evidencia una fuerte dependencia temporal en los eventos reportados, donde los patrones de tráfico diario influyen directamente en su aparición.

7 Análisis para evento PELIGRO

Para profundizar en la variabilidad temporal, se seleccionan únicamente los eventos de tipo PELIGRO ocurridos en el día 26.
Este filtrado permite observar de forma focalizada cómo se comportan los eventos de riesgo dentro de un día específico, tal como se realiza en el cuaderno original de Territorios IA.

eventos_peligro_26 <- Trama_Waze %>%
  filter(tipo_evento == "PELIGRO",
         dia == 26)

eventos_peligro_26
ggplot(eventos_peligro_26, aes(x = hora)) +
  geom_histogram(binwidth = 1, fill = "#1b9e77", color = "white") +
  theme_minimal() +
  labs(title = "Eventos de PELIGRO reportados el día 26",
       x = "Hora del día", y = "Frecuencia")

Los eventos de PELIGRO registrados el día 26 muestran una concentración más marcada entre las horas del mediodía y la tarde, lo cual coincide con los momentos de mayor actividad vehicular y, por ende, mayor probabilidad de que los usuarios detecten y reporten riesgos en la vía. En horas de madrugada los reportes disminuyen considerablemente, reflejando una menor circulación. Este patrón temporal es coherente con el comportamiento general observado en la base completa y refuerza la relación entre actividad vehicular y reporte de peligros.

if (!requireNamespace("leaflet", quietly = TRUE)) install.packages("leaflet")
if (!requireNamespace("mapview", quietly = TRUE)) install.packages("mapview")
library(leaflet)
library(mapview)

# eventos_peligro_26 <- Trama_Waze %>% filter(tipo_evento == "PELIGRO", dia == 26)

if (!exists("eventos_peligro_26")) {
  stop("No existe el objeto 'eventos_peligro_26'. Crea el filtro antes de este chunk:\n
       eventos_peligro_26 <- Trama_Waze %>% filter(tipo_evento == 'PELIGRO', dia == 26)")
}

if (!("lat" %in% names(eventos_peligro_26)) | !("long" %in% names(eventos_peligro_26))) {
  eventos_peligro_26$lat  <- eventos_peligro_26$location_y / 10^(nchar(eventos_peligro_26$location_y) - 1)
  eventos_peligro_26$long <- eventos_peligro_26$location_x / 10^(nchar(eventos_peligro_26$location_x) - 3)
}

# Filtro
eventos_peligro_26 <- eventos_peligro_26 %>%
  filter(lat > 4, lat < 5, long > -75, long < -73)

if (nrow(eventos_peligro_26) == 0) {
  stop("No hay eventos PELIGRO en el día 26 dentro del rango geográfico definido.")
}

# etiquetas
eventos_peligro_26$popup <- paste0(
  "<b>Tipo:</b> ", eventos_peligro_26$tipo_evento, "<br/>",
  "<b>Fecha:</b> ", format(eventos_peligro_26$fecha_hora, "%Y-%m-%d %H:%M"), "<br/>",
  ifelse(!is.na(eventos_peligro_26$información_adicional),
         paste0("<b>Info:</b> ", eventos_peligro_26$información_adicional, "<br/>"), "")
)

# mapa interactivo
m26_peligro <- leaflet(eventos_peligro_26) %>%
  addProviderTiles(providers$OpenStreetMap) %>%
  addCircleMarkers(
    lng = ~long, lat = ~lat,
    radius = 6,
    stroke = FALSE,
    fillOpacity = 0.7,
    clusterOptions = markerClusterOptions(),
    popup = ~popup,
    label = ~paste0("Hora: ", hora)
  ) %>%
  addControl(html = "<h3>Mapa de Riesgos (PELIGRO) - Día 26</h3>", position = "topleft")

# Mapa
m26_peligro
# mapview::mapview(eventos_peligro_26, xcol = "long", ycol = "lat", crs = 4326, zcol = "hora")

El mapa de riesgos para los eventos de tipo PELIGRO del día 26 muestra una clara concentración espacial sobre corredores viales principales, especialmente a lo largo de la Autopista Norte —incluyendo sectores como Cajicá, Canelón, Calahorra, Río Grande y Briceño— donde se observan clústeres bien definidos mediante los marcadores agrupados. La distribución no es aleatoria: los puntos aparecen sistemáticamente agrupados en zonas de alta movilidad y en intersecciones estratégicas, lo que indica un patrón espacial agregado asociado a condiciones viales. Este comportamiento sugiere que estas áreas presentan una mayor probabilidad de incidentes y representan zonas críticas de riesgo, siendo puntos clave para priorizar acciones preventivas, señalización reforzada y monitoreo continuo.

7.1 Análisis espacial de la distribución de eventos (Evento PELIGRO)

El análisis espacial permite estudiar la distribución geográfica de los eventos reportados en la ciudad y evaluar si presentan patrones de concentración, dispersión o aleatoriedad. Esto es fundamental en movilidad, pues identificar zonas críticas ayuda a priorizar intervenciones, optimizar la gestión del tráfico y mejorar la seguridad vial. Siguiendo la metodología utilizada en Paula Moraga (Spatial Statistics and Geostatistics) y en el Cuaderno de Analítica de Movilidad de Territorios IA, se analizan los eventos del día 26 para los tipos PELIGRO y VÍA CERRADA.

# Cargar librerías
library(leaflet)
library(leaflet.extras)
library(dplyr)

# Filtrar eventos PELIGRO del día 26
peligro26 <- Trama_Waze %>% 
  filter(tipo_evento == "PELIGRO", dia == 26)

# Ajuste de coordenadas
peligro26$lat  <- peligro26$location_y / 10^(nchar(peligro26$location_y) - 1)
peligro26$long <- peligro26$location_x / 10^(nchar(peligro26$location_x) - 3)

# Filtro geográfico
peligro26 <- peligro26 %>% 
  filter(lat > 4 & lat < 5, long > -75 & long < -73)

# Mapa de calor
leaflet(peligro26) %>%
  addProviderTiles("OpenStreetMap") %>%
  addHeatmap(
    lng = ~long, lat = ~lat,
    intensity = ~hora,
    blur = 20,
    max = 0.08,
    radius = 15
  ) %>%
  addLegend(
    "bottomright",
    title = "Mapa de Calor de Riesgos",
    colors = c("blue", "green", "yellow", "red"),
    labels = c("Bajo", "Moderado", "Alto", "Muy Alto")
  )

8 Análisis para evento (CIERRE DE VIAS)

8.1 Mapa de Densidad de Cierres de Vías (VÍA CERRADA – Día 26)

En esta sección se muestran los eventos de cierre de vías del día 26 para identificar la concentración espacial de estos sucesos.

# Filtrar eventos VÍA CERRADA
via_cerrada_26 <- Trama_Waze %>%
  filter(tipo_evento == "VÍA CERRADA", dia == 26)

# Ajustar coordenadas
via_cerrada_26$lat  <- via_cerrada_26$location_y / 10^(nchar(via_cerrada_26$location_y) - 1)
via_cerrada_26$long <- via_cerrada_26$location_x / 10^(nchar(via_cerrada_26$location_x) - 3)

# Filtro geográfico
via_cerrada_26 <- via_cerrada_26 %>% 
  filter(lat > 4 & lat < 5)
library(leaflet)

leaflet(via_cerrada_26) %>%
  addTiles() %>%
  addCircleMarkers(
    lng = ~long, lat = ~lat,
    clusterOptions = markerClusterOptions(),
    label = ~hora
  ) %>%
  addControl("<h3>Mapa de Cierre de Vías</h3>", position = "topleft")

El mapa de cierres viales del día 26 muestra que estos eventos no están distribuidos aleatoriamente, sino que se concentran en unas pocas zonas específicas del municipio. La presencia de un grupo grande de reportes —como el que aparece con más de 600 cierres en la parte suroccidental de Cajicá— indica que ese sector tuvo un problema importante, posiblemente relacionado con obras, bloqueos prolongados o alguna situación que afectó varias rutas al mismo tiempo. En otras zonas aparecen cierres aislados, pero la mayor parte se agrupa en áreas puntuales, lo que evidencia un patrón concentrado o agregado. Esto es útil para entender qué partes del municipio requieren mayor atención, refuerzo operativo o mejoras en la movilidad.

8.2 Análisis Espacial de Cierres de Vías

En esta parte se emplean herramientas de análisis espacial para estudiar la distribución geográfica de los cierres de vías del día 26.

8.3 Test de Cuadrantes y Función K

# Cargar librerías correctas
library(spatstat.geom)
library(spatstat.explore)

# Definir ventana de análisis
zona <- owin(
  xrange = c(-74.04331, -73.9929),
  yrange = c(4.885736, 4.948562)
)

# Crear patrón de puntos
patron_via_cerrada <- ppp(
  x = via_cerrada_26$long,
  y = via_cerrada_26$lat,
  window = zona
)

# Test de cuadrantes
plot(quadratcount(patron_via_cerrada), 
     main = "Patrón de Puntos y Test de Cuadrantes")
points(patron_via_cerrada, col = "red")

# Función K
plot(Kest(patron_via_cerrada),
     main = "Función K - Cierres de Vías")

El grafico evidencia que el patrón es agregado para el evento CIERRE DE VIAS

8.4 Mapa de Densidad de Cierres de Vías (KDE)

library(terra)

# Densidad KDE
densidad <- density(patron_via_cerrada, sigma = 0.01)

# Convertir a raster
r_dens <- rast(densidad)

# Convertir a data.frame
df_dens <- as.data.frame(r_dens, xy = TRUE)
colnames(df_dens) <- c("long", "lat", "intensity")

# Normalizar
df_dens$intensity <- (df_dens$intensity - min(df_dens$intensity)) /
                     (max(df_dens$intensity) - min(df_dens$intensity))

# Mapa
leaflet(df_dens) %>%
  addProviderTiles("OpenStreetMap") %>%
  addHeatmap(
    lng = ~long, lat = ~lat,
    intensity = ~intensity,
    blur = 20,
    max = 1,
    radius = 15
  ) %>%
  addLegend(
    "bottomright",
    title = "Mapa de Calor de Cierres de Vías",
    colors = c("blue", "green", "yellow", "red"),
    labels = c("Bajo", "Moderado", "Alto", "Muy Alto")
  )

9 Análisis para evento Accidentes

En esta sección se realiza un análisis detallado de los eventos clasificados como ACCIDENTE ocurridos el día 26. El objetivo es identificar su distribución espacial, localizar zonas críticas y evaluar patrones que puedan afectar la movilidad urbana. Este tipo de análisis es fundamental para apoyar decisiones en seguridad vial, infraestructura, señalización y gestión del tráfico.

9.1 Filtrado de Accidentes del Día 26

Se seleccionan únicamente los eventos de tipo ACCIDENTE correspondientes a la fecha de interés y se ajustan sus coordenadas para garantizar una correcta visualización.

Trama_Waze$fecha_hora <- as.POSIXct(Trama_Waze$creation_Date)
Trama_Waze$dia  <- lubridate::day(Trama_Waze$fecha_hora)
Trama_Waze$hora <- lubridate::hour(Trama_Waze$fecha_hora)

# Filtrar eventos ACCIDENTE del día 26
pos <- which(Trama_Waze$tipo_evento == "ACCIDENTE" & Trama_Waze$dia == 26)
accidente_26 <- Trama_Waze[pos,]

# Ajustar coordenadas
accidente_26$lat  <- accidente_26$location_y / 10^(nchar(accidente_26$location_y) - 1)
accidente_26$long <- accidente_26$location_x / 10^(nchar(accidente_26$location_x) - 3)

# Filtro geográfico
accidente_26 <- accidente_26[accidente_26$lat > 4 & accidente_26$lat < 5,]

Este mapa presenta los puntos donde ocurrieron accidentes el día 26. Cada marcador incluye la hora del evento.

library(leaflet)

m26_accidente <- leaflet(accidente_26) %>%
  addTiles() %>%
  addCircleMarkers(lng = ~long, lat = ~lat,
                   clusterOptions = markerClusterOptions(),
                   label = ~hora) %>%
  addControl(html = "<h3>Mapa de Accidentes</h3>", position = "topleft")

m26_accidente

9.2 Analisis espacial de accidentes

require(spatstat)

# zona de análisis
zona <- owin(xrange = c(-74.04331, -73.9929),
             yrange = c(4.885736, 4.948562))

# Patrón de puntos
patron_accidente <- ppp(x = accidente_26$long,
                        y = accidente_26$lat,
                        window = zona)

# Gráfico test de cuadrantes
par(mfrow = c(1,1))
plot(quadratcount(patron_accidente),
     main = "Patrón de puntos y test de cuadrantes")
points(patron_accidente, col = "red")

# Función K
plot(Kest(patron_accidente),
     main = "Función K - Accidentes día 26")

Según el gráfico, para el evento de accidentes el patrón supone un patrón agregado

9.3 Mapa de densidad

library(terra)
library(spatstat)
library(leaflet)

# Calcular densidad
im1 <- density(patron_accidente)

# Convertir a raster
mapa_accidente <- rast(im1)

# Convertir a data.frame para leaflet
df_accidente <- as.data.frame(mapa_accidente, xy = TRUE)
colnames(df_accidente) <- c("long", "lat", "intensity")

# Normalizar
df_accidente$intensity <- (df_accidente$intensity - min(df_accidente$intensity)) /
                          (max(df_accidente$intensity) - min(df_accidente$intensity))

# Mapa de calor
leaflet(df_accidente) %>%
  addProviderTiles("OpenStreetMap") %>%
  addHeatmap(
    lng = ~long, lat = ~lat,
    intensity = ~intensity,
    blur = 15,
    radius = 10,
    max = 0.5
  ) %>%
  addLegend("bottomright",
            title = "Mapa de Calor de Accidentes",
            colors = c("blue","green","yellow","red"),
            labels = c("Bajo", "Moderado", "Alto", "Muy Alto"))

10 Análisis de Congestión el Día 26

En esta sección se analiza la congestión reportada el día 26. Se filtran los eventos de congestión para centrarse en los reportes de ese día y se estudia cómo se distribuyen en términos espaciales y temporales.

El análisis de la congestión es vital para la planificación del tráfico en una ciudad ya que permite identificar las áreas donde el tráfico es más denso y los momentos del día en que se presentan mayores problemas de movilidad. Estos datos pueden ser utilizados para optimizar la programación de semáforos o la gestión de rutas alternas.

library(lubridate)

# formato de fecha
Trama_Waze$creation_Date <- as.POSIXct(
  Trama_Waze$creation_Date,
  format = "%Y-%m-%d %H:%M:%S",
  tz = "UTC"
)

# Extraer el día
Trama_Waze$dia <- day(Trama_Waze$creation_Date)

10.1 Filtrado y preparación de los datos

# Filtrar eventos de congestión del día 26
pos <- which(Trama_Waze$tipo_evento == "CONGESTIÓN" & Trama_Waze$dia == 26)
congestion_26 <- Trama_Waze[pos,]

# Ajustar coordenadas de latitud y longitud
congestion_26$lat <- congestion_26$location_y / 10^(nchar(congestion_26$location_y) - 1)
congestion_26$long <- congestion_26$location_x / 10^(nchar(congestion_26$location_x) - 3)

# Filtrar eventos dentro del rango geográfico adecuado
congestion_26 <- congestion_26[congestion_26$lat > 4 & congestion_26$lat < 5,]

10.2 Mapa interactivo de congestión

library(leaflet)

# Crear el mapa interactivo
m26_congestion <- leaflet(congestion_26) %>%
  addTiles() %>%
  addCircleMarkers(
    lng = ~long, lat = ~lat,
    clusterOptions = markerClusterOptions(),
    label = ~hora
  ) %>%
  addControl(html = "<h3>Mapa de Congestión</h3>", position = "topleft")

# Mostrar el mapa
m26_congestion

10.3 Análisis espacial

library(spatstat.geom)
library(spatstat.explore)

# Definir zona de interés
zona <- owin(xrange = c(-74.04331, -73.9929),
             yrange = c(4.885736, 4.948562))

# Crear patrón de puntos
patron_congestion <- ppp(
  x = congestion_26$long,
  y = congestion_26$lat,
  window = zona
)

# Test de cuadrantes
plot(quadratcount(patron_congestion),
     main = "Patrón de Puntos y Test de Cuadrantes")
points(patron_congestion, col = "red")

# Función K de Ripley
plot(Kest(patron_congestion),
     main = "Función K para eventos de congestión")

El evento presenta que el patron es agregado para el evento congestión

10.4 Mapa de Densidad

library(terra)
library(leaflet)

# Calcular densidad
im1 <- density(patron_congestion)

# Convertir densidad a raster de terra
mapa_congestion <- rast(im1)

# Convertir raster a data.frame
df_congestion <- as.data.frame(mapa_congestion, xy = TRUE)
colnames(df_congestion) <- c("long", "lat", "intensity")

# Normalizar intensidad
df_congestion$intensity <- (df_congestion$intensity - min(df_congestion$intensity)) /
                           (max(df_congestion$intensity) - min(df_congestion$intensity))

# Crear mapa de calor
leaflet(df_congestion) %>%
  addProviderTiles("OpenStreetMap") %>%
  addHeatmap(
    lng = ~long, lat = ~lat,
    intensity = ~intensity,
    blur = 35,
    max = max(df_congestion$intensity) * 2,
    radius = 25
  ) %>%
  addLegend(
    "bottomright",
    title = "Mapa de Calor de Congestión",
    colors = c("blue", "green", "yellow", "red"),
    labels = c("Bajo", "Moderado", "Alto", "Muy Alto")
  )

11 Consolidación de Mapas de Peligro, Accidentes, Congestión y Cierres Viales

Esta sección integra en una sola vista los mapas interactivos generados previamente para los cuatro tipos de eventos analizados: PELIGRO, ACCIDENTE, CONGESTIÓN y VÍA CERRADA. La sincronización de mapas permite observar simultáneamente los patrones espaciales de cada categoría, facilitando la comparación visual y la identificación de zonas donde coinciden múltiples problemáticas de movilidad.

Esta integración es útil para la toma de decisiones, ya que brinda una perspectiva global de los eventos reportados en la ciudad.

# Filtrar eventos VÍA CERRADA del día 26
pos <- which(Trama_Waze$tipo_evento == "VÍA CERRADA" & Trama_Waze$dia == 26)
via_cerrada_26 <- Trama_Waze[pos,]

# Ajustar coordenadas
via_cerrada_26$lat <- via_cerrada_26$location_y / 10^(nchar(via_cerrada_26$location_y) - 1)
via_cerrada_26$long <- via_cerrada_26$location_x / 10^(nchar(via_cerrada_26$location_x) - 3)

# Filtrar rango geográfico
via_cerrada_26 <- via_cerrada_26[via_cerrada_26$lat > 4 & via_cerrada_26$lat < 5,]

# Cargar leaflet
library(leaflet)

# Crear mapa interactivo
m26_via_cerrada <- leaflet(via_cerrada_26) %>%
  addTiles() %>%
  addCircleMarkers(
    lng = ~long, lat = ~lat,
    clusterOptions = markerClusterOptions(),
    label = ~hora
  ) %>%
  addControl(html = "<h3>Mapa de Cierre de Vías</h3>", position = "topleft")
# Cargar librería necesaria para sincronizar mapas leaflet
library(leafsync)

leafsync::sync(
  m26_peligro,
  m26_accidente,
  m26_congestion,
  m26_via_cerrada
)

12 Conclusión

El análisis espacial realizado mediante el test de cuadrantes y la función K de Ripley muestra que los eventos reportados por Waze el día 26 no siguen un patrón aleatorio. En los cuatro tipos de eventos —PELIGRO, ACCIDENTE, CONGESTIÓN y VÍA CERRADA— se observa que la curva estimada de la función K se encuentra por encima de la banda teórica de complete spatial randomness (CSR), lo que indica una clara tendencia a la agregación.

Los mapas de densidad generados mediante estimación kernel confirman este comportamiento, evidenciando zonas específicas donde los eventos tienden a concentrarse, particularmente sobre corredores viales principales y sectores con alta actividad vehicular. Este patrón agregado sugiere que los eventos no ocurren de manera uniforme ni regular en el espacio, sino que se concentran en áreas críticas determinadas por la infraestructura vial, volumen de tráfico y características propias de la movilidad urbana.

En síntesis, el patrón espacial de los eventos analizados es predominantemente agregado, lo que implica que existen puntos calientes (“hotspots”) donde la probabilidad de ocurrencia es significativamente mayor que en otras zonas. Esto representa información valiosa para priorizar intervenciones, mejorar la infraestructura, reforzar la señalización y orientar estrategias de gestión del tráfico basadas en evidencia espacial.