Introducción

El presente informe realiza un análisis exploratorio y diagnóstico de los accidentes de tránsito registrados en carreteras nacionales. El objetivo principal es identificar cuáles son las causas más comunes, los tipos de accidentes más críticos y las zonas o condiciones viales que presentan mayor peligrosidad, permitiendo generar recomendaciones basadas en datos para la seguridad vial.

Análisis Exploratorio de Datos (EDA)

El Análisis Exploratorio de Datos (EDA) es el pilar metodológico clave para transformar los registros brutos de accidentes en información con valor estratégico. Este procedimiento nos permite: * Identificar patrones viales: Detectar las causas y los tipos de accidentes más recurrentes. * Evaluar distribuciones: Analizar el comportamiento de las variables críticas (muertos, heridos, vehículos involucrados). * Descubrir anomalías: Detectar de forma temprana sesgos, valores atípicos o nulos que requieran depuración.

PASO 1. Instalar y cargar librerias

# Cargar librerías necesarias
library(readxl)
library(dplyr)
library(ggplot2)
library(plotly)
library(knitr)
library(kableExtra)
library(tidyr)
library(RecordLinkage)
library(leaflet)
library(htmltools)

PASO 2: Filtrar o seleccionar la información que necesito

Se filtra la base de datos para trabajar con un subconjunto específico. En este caso, seleccionaremos los accidentes ocurridos en el estado de São Paulo (“SP”) que tuvieron como resultado víctimas heridas o muertas.

library(readxl)
datos <- read_excel("Accidentes.xlsx")

# Filtro de información aproximada
require(RecordLinkage)

pos = which(jarowinkler("JACAREI", datos$municipio) > 0.95 & datos$uf == "SP")
datos_sub = datos[pos, ]
head(datos_sub)
id Fecha hora uf municipio causa_accidente tipo_acidente clasificación_accidente sentido_via tipo_pista Personas Muertos Herido_Leves Heridos_graves ilesos ignorados Heridos vehículos latitude longitude
264173 2020-01-21 1899-12-31 08:05:00 SP JACAREI Falta de atención de conducción Colisión trasera Con víctimas heridas DeCreciente Dupla 2 0 1 0 1 0 1 2 -23.26072 -45.95179
107162 2018-01-29 1899-12-31 17:30:00 SP JACAREI Falta de atención de conducción Colisión trasera Con víctimas heridas DeCreciente Dupla 2 0 1 0 1 0 1 2 -23.33077 -46.12942
230761 2019-08-24 1899-12-31 10:15:00 SP JACAREI Falta de atención de conducción Colisión trasera Con víctimas heridas DeCreciente Dupla 2 0 1 0 1 0 1 2 -23.26585 -45.95984
259619 2019-12-30 1899-12-31 08:40:00 SP JACAREI Falta de atención de conducción Colisión trasera Con víctimas heridas Creciente Dupla 2 0 1 0 1 0 1 2 -23.30546 -46.03568
146175 2018-07-12 1899-12-31 17:35:00 SP JACAREI Falta de atención de conducción Colisión lateral Con víctimas heridas DeCreciente Dupla 2 0 1 0 1 0 1 2 -23.27458 -45.97336
135683 2018-05-21 1899-12-31 07:40:00 SP JACAREI Falta de atención de conducción Colisión lateral Con víctimas heridas DeCreciente Dupla 2 0 1 0 1 0 1 2 -23.28077 -45.98328

Ahora obtenemos los nombres exactos de las variables que tenemos en la base de datos

library(dplyr)
names(datos_sub)
##  [1] "id"                      "Fecha"                  
##  [3] "hora"                    "uf"                     
##  [5] "municipio"               "causa_accidente"        
##  [7] "tipo_acidente"           "clasificación_accidente"
##  [9] "sentido_via"             "tipo_pista"             
## [11] "Personas"                "Muertos"                
## [13] "Herido_Leves"            "Heridos_graves"         
## [15] "ilesos"                  "ignorados"              
## [17] "Heridos"                 "vehículos"              
## [19] "latitude"                "longitude"
## Registros totales para los accidentes en el municipio de Jacareí (SP)
length(pos)
## [1] 254

Indicadores de centralidad

# na.rm = TRUE: ignora valores faltantes (NA) para evitar errores en el cálculo.
cantidad_accidentes = length(datos_sub$id)
promedio_personas   = mean(datos_sub$Personas, na.rm = TRUE)
promedio_muertos    = mean(datos_sub$Muertos, na.rm = TRUE)
promedio_heridos    = mean(datos_sub$Heridos, na.rm = TRUE)

# Usamos [[18]] para llamar a la columna 'vehículos' por su posición sin activar el error de la tilde
promedio_vehiculos  = mean(datos_sub[[18]], na.rm = TRUE)

resultado_prom = data.frame(cantidad_accidentes, promedio_personas, promedio_muertos, promedio_heridos, promedio_vehiculos)
resultado_prom
cantidad_accidentes promedio_personas promedio_muertos promedio_heridos promedio_vehiculos
254 2.232283 0.0669291 0.980315 1.582677
# Calculamos la mediana para entender el comportamiento del caso típico central
cantidad_accidentes = length(datos_sub$id)
mediana_personas    = median(datos_sub$Personas, na.rm = TRUE)
mediana_muertos     = median(datos_sub$Muertos, na.rm = TRUE)
mediana_heridos     = median(datos_sub$Heridos, na.rm = TRUE)

# Usamos [[18]] nuevamente para la mediana de vehículos
mediana_vehiculos   = median(datos_sub[[18]], na.rm = TRUE)

resultado_med = data.frame(cantidad_accidentes, mediana_personas, mediana_muertos, mediana_heridos, mediana_vehiculos)
resultado_med
cantidad_accidentes mediana_personas mediana_muertos mediana_heridos mediana_vehiculos
254 2 0 1 1
# Calculamos los estadísticos descriptivos para el total de personas involucradas
promedio_personas = mean(datos_sub$Personas, na.rm = TRUE)
mediana_personas  = median(datos_sub$Personas, na.rm = TRUE)
minimo_personas   = min(datos_sub$Personas, na.rm = TRUE)
maximo_personas   = max(datos_sub$Personas, na.rm = TRUE)
desvest_personas  = sd(datos_sub$Personas, na.rm = TRUE)

# Consolidamos los indicadores en un dataframe
indic_personas = data.frame(promedio_personas, mediana_personas, minimo_personas, maximo_personas, desvest_personas)
indic_personas
promedio_personas mediana_personas minimo_personas maximo_personas desvest_personas
2.232283 2 1 24 1.977437
# Calculamos los estadísticos descriptivos para el total de personas heridas
promedio_heridos = mean(datos_sub$Heridos, na.rm = TRUE)
mediana_heridos  = median(datos_sub$Heridos, na.rm = TRUE)
minimo_heridos   = min(datos_sub$Heridos, na.rm = TRUE)
maximo_heridos   = max(datos_sub$Heridos, na.rm = TRUE)
desvest_heridos  = sd(datos_sub$Heridos, na.rm = TRUE)

# Consolidamos los indicadores asegurando que llamamos a las variables correctas
indic_heridos = data.frame(promedio_heridos, mediana_heridos, minimo_heridos, maximo_heridos, desvest_heridos)
indic_heridos
promedio_heridos mediana_heridos minimo_heridos maximo_heridos desvest_heridos
0.980315 1 0 7 1.068599

Representación gráfica

1. Gráfico de Barras de Frecuencias

Para una variable cuantitativa discreta como el número de personas involucradas, el gráfico de barras nos permite observar con precisión cuántos accidentes ocurrieron para cada conteo específico, sin agrupar ni perder información en rangos artificiales.

# Crear el gráfico base con ggplot2
grafico_barras <- ggplot(datos_sub, aes(x = factor(Personas))) +
  geom_bar(fill = "steelblue", color = "black", alpha = 0.7, width = 0.7) +
  labs(
    title = "Figura 1. Frecuencia Absoluta de Accidentes segun Personas Involucradas en Jacarei",
    x = "Numero de Personas Involucradas (Conteo Exacto)", 
    y = "Cantidad de Accidentes Registrados"
  ) +
  theme_minimal() +
  theme(
    plot.title = element_text(face = "bold", size = 12, hjust = 0.5),
    axis.title = element_text(face = "bold"),
    panel.grid.minor = element_blank()
  )

# Convertir a gráfico interactivo
ggplotly(grafico_barras)

Interpretación Figura 1.

La Figura 1. muestra la distribución del número de personas involucradas en los accidentes de tránsito registrados en el municipio de Jacareí. Permite identificar patrones, concentración de personas por siniestro y posibles sesgos en la distribución.

📌 Distribución de Personas Involucradas:

La mayoría de los accidentes involucran entre 1 y 3 personas.

Se observa una mayor concentración entre 1 y 2 personas, con los valores más frecuentes en ese rango (lo que representa incidentes cotidianos como choques particulares o caídas de motocicletas).

Hay accidentes con un volumen de personas mucho mayor, superando las 5 personas, pero son menos frecuentes.

📈 Modos y Agrupaciones:

Se identifica un pico principal muy marcado:

El rango de 1 a 2 personas (donde se registra la gran masa operativa de los accidentes).

A partir de 3 personas, la cantidad de casos disminuye de forma drástica, lo que demuestra que los incidentes que afectan a grupos medianos o grandes son eventos aislados en la red vial.

📊 Dispersión y Rango de Personas:

El número de personas involucradas va desde 1 hasta los valores máximos detectados en los siniestros más grandes. La distribución presenta una alta variabilidad en su impacto, mostrando una clara diferencia entre los incidentes cotidianos de escala mínima y los accidentes masivos.

⚠️ Los accidentes que involucran a 5 o más personas parecen ser excepciones en los registros, indicando que son siniestros críticos, colisiones múltiples o eventos de transporte público que representan el mayor desafío para la seguridad vial y la atención de emergencias.

# Crear el gráfico base del Boxplot con ggplot2
grafico_box <- ggplot(datos_sub, aes(y = Personas)) +
  geom_boxplot(fill = "seagreen", color = "black", alpha = 0.6, 
               outlier.color = "red", outlier.shape = 16, outlier.size = 2) +
  labs(
    title = "Figura 2. Diagrama de Caja para la Dispersión y Outliers de Personas Involucradas",
    y = "Número de Personas Involucradas"
  ) +
  theme_minimal() +
  theme(
    plot.title = element_text(face = "bold", size = 12, hjust = 0.5),
    axis.title.y = element_text(face = "bold"),
    axis.text.x = element_blank(), # Oculta el eje X por estética al ser una sola variable
    panel.grid.major.x = element_blank()
  )

# Convertir a gráfico interactivo
ggplotly(grafico_box)

Interpretación Figura 2.

La Figura 2. muestra la dispersión, la posición de los cuartiles y la presencia de valores atípicos para el número de personas involucradas en los accidentes de Jacareí. Permite identificar patrones de variabilidad, la localización del caso típico y la magnitud de los eventos extremos.

📌 Estructura y Concentración Central:

La línea central de la mediana y el cuerpo de la caja (que encierra el 50% de los datos más comunes) se ubican en la parte inferior del gráfico, entre 1 y 2 personas.

Se observa una concentración absoluta en este rango inferior, lo que confirma visualmente que el caso “típico” de siniestralidad en el municipio es de escala muy pequeña.

Hay una distancia muy corta entre el primer cuartil y la mediana, lo que demuestra la homogeneidad en los accidentes de menor impacto.

📈 Modos y Agrupaciones:

El gráfico no muestra barras sino límites estructurales (cuartiles):

El bloque principal (la caja verde) se agrupa firmemente en la base de la escala, mostrando dónde se estabilizan los registros normales.

La ausencia de una caja alargada hacia arriba sugiere que los rangos medianos de personas (por ejemplo, accidentes de 4 o 5 personas) no forman un grupo o modo común, sino que la distribución pasa directamente de la normalidad baja a la excepcionalidad.

📊 Dispersión y Rango de Personas:

Los datos muestran una asimetría positiva extrema (sesgo hacia valores altos), reflejada en la longitud del “bigote” superior y los puntos flotantes. La variable tiene una alta variabilidad total provocada por la distancia entre los accidentes de un solo ocupante y los eventos de gran magnitud en el extremo superior.

⚠️ Los puntos rojos ubicados por encima del bigote superior representan valores atípicos (outliers) en el mercado vial, indicando que los accidentes con altas cifras de personas son excepciones estadísticas que se salen del comportamiento común, requiriendo un análisis de seguridad especializado debido a su alta gravedad.

Exploración bivariada entre Personas Involucradas y Heridos

Gráfico de dispersión con correlación

A continuación, evaluamos la relación existente entre el volumen de personas involucradas en el siniestro y el total de personas que resultaron heridas, permitiendo medir la intensidad y dirección de esta asociación lineal.

# Crear gráfico interactivo bivariado con coeficiente de correlación dinámico
grafico_dispersion <- ggplot(datos_sub, aes(x = Personas, y = Heridos)) +
  geom_point(color = "purple", alpha = 0.6, size = 2.5, position = "jitter") +  # 'jitter' evita que los puntos enteros se encimen por completo
  geom_smooth(method = "loess", color = "grey40", se = TRUE, size = 1) +  
  labs(
    title = paste("Figura 3. Relación entre Personas Involucradas y Cantidad de Heridos\nCoef. de correlación: ", 
                  round(cor(datos_sub$Heridos, datos_sub$Personas, use = "complete.obs"), 2)),
    x = "Total de Personas Involucradas en el Accidente",
    y = "Cantidad de Personas Heridas",
    caption = "Fuente: Registro de Accidentes de Jacareí"
  ) +
  theme_minimal() +
  theme(
    plot.title = element_text(size = 12, face = "bold", hjust = 0.5),
    axis.title = element_text(size = 11, face = "bold"),
    axis.text = element_text(size = 10),
    panel.grid.minor = element_blank()
  )

# Renderizar gráfico interactivo
ggplotly(grafico_dispersion)

Interpretación Figura 3.

Este gráfico muestra la relación entre la cantidad de personas heridas y el total de personas involucradas en los accidentes de tránsito registrados en Jacareí.

🔹 Tendencia general:

Se observa una relación positiva: a mayor número de personas involucradas en el siniestro, mayor suele ser la cantidad de personas heridas. Sin embargo, la relación no es completamente lineal, ya que se presenta una dispersión importante en ciertos rangos debido a la naturaleza de los impactos.

🔹 Patrones clave:

Para accidentes con menos de 3 personas involucradas, los heridos se concentran estrechamente en los rangos más bajos (incidentes cotidianos y choques simples). Entre 3 y 5 personas involucradas, los resultados son más dispersos, registrándose siniestros donde la mayoría resulta ilesa y otros donde las lesiones aumentan rápidamente. *Con más de 5 personas involucradas, el volumen de lesionados tiende a incrementarse significativamente, pero con más variabilidad debido a la presencia de vehículos de transporte masivo o colisiones múltiples.

🔹 Curva de tendencia (línea gris):

La línea suavizada sugiere un crecimiento inicial marcado del número de heridos conforme aumenta la exposición de personas en el choque. Se puede observar una leve estabilización o cambio de pendiente en los rangos más altos, lo que refleja que un mayor número de involucrados no se traduce de manera automática o idéntica en heridos adicionales.

Coeficiente de correlación

A medida que el total de personas involucradas aumenta, la cantidad de heridos también tiende a aumentar. Es una relación directamente proporcional: accidentes que exponen a más ocupantes suelen reportar un saldo de lesionados mayor. La correlación se ubica en un rango positivo y significativo, lo que indica que el tamaño del siniestro explica una parte importante de la gravedad del resultado. Aunque hay variabilidad en las consecuencias físicas, en general, el volumen de personas atrapadas en el evento es un factor clave. Una correlación alta NO significa que la mera presencia de personas cause de forma directa las heridas. Otros factores críticos como la velocidad del impacto, el tipo de vehículo (moto, auto, autobús) y la infraestructura vial también influyen en la gravedad.

El coeficiente de correlación calculado indica que el total de personas involucradas es un buen predictor de la cantidad de heridos, pero no es el único factor determinante.

Hallazgos relevantes

Gravedad marginal: Puede haber un punto de inflexión donde aumentar el número de personas involucradas (por ejemplo, en un autobús) no incrementa los heridos proporcionalmente gracias a la estructura del vehículo.

Vulnerabilidad del actor vial: Los siniestros que muestran barras altas de heridos con muy pocas personas involucradas suelen identificar a los actores más vulnerables (motociclistas y peatones), donde el riesgo de lesión es crítico.

Factores de seguridad (Outliers): Algunos valores atípicos en el gráfico evidencian accidentes con muchos involucrados pero cero o muy pocos heridos, lo que resalta la efectividad de los sistemas de seguridad pasiva o impactos ocurridos a muy baja velocidad.

El total de personas involucradas es un fuerte predictor de la cantidad de heridos, pero hay variaciones estructurales que se explican por otros factores como la velocidad de circulación, el tipo de colisión y el uso de elementos de protección (casco, cinturón y airbags).

Representación espacial de la información

# Inicia la creación del mapa interactivo con las columnas corregidas
leaflet() %>% 
  addCircleMarkers(
    lng = datos_sub$longitude, # Columna exacta de longitud de tu archivo
    lat = datos_sub$latitude,  # Columna exacta de latitud de tu archivo
    radius = 1.5,              # Tamaño sutil del marcador para evitar saturación visual
    color = "purple",          # Color distintivo para los puntos de los accidentes
    opacity = 0.7,             # Opacidad para identificar zonas donde los puntos se traslapan
    label = datos_sub$id       # Muestra el ID del accidente al pasar el cursor
  ) %>% 
  addTiles()                   # Añade la capa de mapa base (OpenStreetMap)
# Creación del mapa interactivo libre de errores de codificación (UTF-8)
leaflet() %>% 
  addCircleMarkers(
    lng = datos_sub$longitude, 
    lat = datos_sub$latitude, 
    radius = 2.0,              
    color = "purple",          
    opacity = 0.8,
    label = paste0(
      'ID Siniestro: ', datos_sub$id,
      ', Total Personas: ', datos_sub$Personas, 
      ', Heridos: ', datos_sub$Heridos, 
      ', Vehiculos: ', datos_sub[[18]], # Texto limpio sin tilde para evitar el error
      ', Lat: ', datos_sub$latitude,
      ', Long: ', datos_sub$longitude
    )
  ) %>% 
  addTiles()