Comparendos en Barranquilla (abril–mayo 2010): Quién, Qué, Cuándo y Cuántas veces

Introducción

Los comparendos de tránsito son el instrumento con el que las autoridades sancionan las infracciones a las normas de circulación y, a la vez, una fuente de datos que permite entender quiénes las cometen, cuándo y con qué frecuencia. Analizar esa información ayuda a decidir dónde reforzar los controles y a quién dirigir las campañas de prevención.

Este informe analiza la base de datos de comparendos de la ciudad de Barranquilla (Atlántico) registrados entre el 12 de abril y el 27 de mayo de 2010. La base contiene 2.120 registros y 17 columnas, que reúnen información del titular (nombre, tipo y número de identificación, sexo o tipo de persona), del vehículo (placa y tipo), de la infracción (código, número de comparendo y fecha) y del cobro (número y fecha del mandamiento de pago y valor a pagar).

El análisis se desarrolla en lenguaje R dentro de un documento R Markdown, con los paquetes dplyr para manipular los datos, readxl para leer el archivo de Excel y ggplot2 para los gráficos. Primero se prepara y depura la base; luego se responden cuatro preguntas (quién, qué, cuándo y cuántas veces) con tablas y gráficos, y el informe cierra con conclusiones y recomendaciones.

De qué trata este informe

En lugar de describir variable por variable, este informe parte de cuatro preguntas sobre los comparendos de tránsito de Barranquilla registrados entre abril y mayo de 2010:

  1. ¿Quién recibe los comparendos (personas naturales o empresas)?
  2. ¿Qué infracciones se cometen y cuánto representan en dinero?
  3. ¿Cuándo ocurren (día de la semana y evolución por semanas)?
  4. ¿Cuántas veces se repiten las mismas personas y vehículos (reincidencia)?

Datos y preparación

BD <- read_excel("BD Comparendos OK$.xlsx")
names(BD) <- trimws(names(BD))   # algunas columnas traen espacios al final

nombres_dia <- c("Lunes", "Martes", "Miércoles", "Jueves", "Viernes", "Sábado", "Domingo")

comp <- BD %>%  #tomamos el data.frame BD y con el operador pipe %>% lo pasamos a la siguiente funcion
  transmute(    #transmute crea un nuevo data.frame conservando solo las columnas que definamos (elimina las demas)
    ejecutado = EJECUTADO,                    #renombramos la columna EJECUTADO a ejecutado
    tipo_id   = `TIPO DE IDENTIFICACION`,     #renombramos la columna TIPO DE IDENTIFICACION a tipo_id
    id        = `No. IDENTIFICACION`,         #renombramos la columna No. IDENTIFICACION a id
    sexo      = SEXO,                         #renombramos la columna SEXO a sexo
    cod_inf   = `COD. INFRACCION`,            #renombramos la columna COD. INFRACCION a cod_inf
    num_comp  = COMPARENDO,                   #renombramos la columna COMPARENDO a num_comp

    # La columna FECHA original trae día y mes invertidos: se usa FECHA DE COMPARENDO
    fecha     = as.Date(as.numeric(`FECHA DE COMPARENDO`), origin = "1899-12-30"),
    placa     = `PACA DE VEHICULO`, #renombramos
    vehiculo  = `TIPO DE VEHICULO`,
    valor     = VALOR_A_PAGAR
  ) %>%
  
  mutate(  #mutate agrega una nueva columna al data.frame sin eliminar las existentes
    persona = if_else(sexo == "EMPRESA", "Persona jurídica", "Persona natural"),  #if_else evalua una condicion: si sexo es "EMPRESA" asigna "Persona jurídica", de lo contrario asigna "Persona natural", y guarda el resultado en la nueva columna persona
  
  
      infraccion = case_when(  #case_when evalua multiples condiciones en orden y asigna un valor segun la primera que se cumpla
        cod_inf == 64 ~ "Exceso de velocidad",          
        cod_inf == 77 ~ "Omitir luz roja o PARE",       
        cod_inf == 67 ~ "Detenerse sobre la cebra",      
        cod_inf == 76 ~ "Transitar en sentido contrario",
        TRUE ~ as.character(cod_inf)                    
#TRUE actua como "en cualquier otro caso", convierte el codigo numerico a texto y lo deja tal cual
      ),
  
  
  
dia_sem    = factor(nombres_dia[as.integer(format(fecha, "%u"))], levels = nombres_dia),
  #agregamos valores a la variable dia_sem, pedimos con la funcion %u 
  #que nos devuelva el numero del dia como texto por eso se convierte en entero con as.interger y por ultimo 
  #lo ordenamos con levels para que estè con el orden de nombres_dia.

semana_ini = fecha - (as.integer(format(fecha, "%u")) - 1)   
  )
  #La funcion hace que el numero del dia en el que estemos sea un entero y le restamos 1, y ese numero
  #se le resta a la fecha dando como resultado el mismo lunes para volver al lunes  de la semana a la que pertenece. 

# Etiqueta de semana (la primera semana queda arriba en el mapa de calor)

semanas <- sort(unique(comp$semana_ini)) #extraemos la columna semana_ini que pertence al data.frame comp con  unique extraemos solo los valores unicos de esa variable  (sin orden garantizado),sort organiza de mayor a menor.

comp$semana_txt <- factor(format(comp$semana_ini, "%d/%m"),
#extraemos nuevamente la columna semana_ini que pertenece al data.frame aquí si se extraen todas las filas %d representa el dia del mes con dos digitos (01,02...,31) separado por una barra y el %m representa el numero del mes con dos dijitos igualmente, el resultado de este formato es algo como "05/05", "12/01","31/12", etc. la funcion format convierte el tipo date a un string de texto segun el patrón indicado: la columna extraida es el valor a convertir  y los patrones son %d y %m.
                      levels = rev(format(semanas, "%d/%m")))
# el rev revierte las posiciones de un vector, el ultimo valor pasa a ser el primero y viceversa. levels indica cuales van a ser los niveles del factor. Un factor se compone de categorias o niveles y ahi se lo especificamos 

Panorama general

tibble(  #tibble crea una tabla (data.frame moderno) con las columnas que definamos
  Indicador = c("Comparendos registrados", "Personas o empresas distintas",  #c() concatena los textos en un vector, sera la primera columna con los nombres de cada indicador
                "Vehículos (placas) distintos", "Primer comparendo",
                "Último comparendo", "Valor por comparendo", "Total a pagar"),
  Valor = c(fmt(nrow(comp)), fmt(n_distinct(comp$id)), fmt(n_distinct(comp$placa)),  #segunda columna con los valores calculados:
#fmt(nrow(comp)) cuenta el total de filas (comparendos) y le da formato            #fmt(n_distinct(comp$id)) cuenta los ids unicos (personas/empresas distintas)
#fmt(n_distinct(comp$placa)) cuenta las placas unicas (vehiculos distintos)
            format(min(comp$fecha), "%d/%m/%Y"), format(max(comp$fecha), "%d/%m/%Y"),  
#min() y max() obtienen la primera y ultima fecha, format() las convierte a texto dd/mm/aaaa
            dinero(unique(comp$valor)), dinero(sum(comp$valor)))  
#dinero() formatea como moneda: el valor unico por comparendo y la suma total
) %>% kable()  #el pipe pasa la tabla a kable() que la convierte en una tabla con mejor diseño para mostrar en el reporte
Indicador Valor
Comparendos registrados 2.120
Personas o empresas distintas 1.251
Vehículos (placas) distintos 1.457
Primer comparendo 12/04/2010
Último comparendo 27/05/2010
Valor por comparendo $438.900
Total a pagar $930.468.000

¿Quién recibe los comparendos?

quien <- comp %>%  #crea un nuevo objeto llamado quien con los datos de comp
  count(persona, sexo) %>%  #count() cuenta las filas agrupando por persona (natural/juridica) y sexo, genera columnas: persona, sexo, n
  mutate(porcentaje = 100 * n / sum(n))  #crea columna porcentaje: calcula el porcentaje de cada grupo sobre el total

kable(quien, digits = 1, col.names = c("Tipo de titular", "Categoría en la base", "Comparendos", "% del total"))  #muestra la tabla en formato HTML con 1 decimal, renombrando las columnas
Tipo de titular Categoría en la base Comparendos % del total
Persona jurídica EMPRESA 472 22.3
Persona natural CÉDULA NUEVA 88 4.2
Persona natural HOMBRE 615 29.0
Persona natural MUJER 945 44.6
ggplot(quien, aes(x = reorder(sexo, n), y = n, fill = persona)) +  #inicia grafico: reorder(sexo, n) ordena las barras por cantidad, fill=pinta las barras segun tipo de persona
  geom_col() +  #agrega barras verticales
  geom_text(aes(label = fmt(n)), hjust = -0.2) +  #agrega etiquetas con la cantidad de comparendos, hjust las corre hacia la derecha de la barra
  coord_flip() +  #voltea el grafico (barras horizontales)
  scale_fill_manual(values = c(  #asigna colores manuales a cada tipo de persona
  "Persona natural" = "#705D9E",  #morado para persona natural
  "Persona jurídica" = "#E88C68"  #naranja para persona juridica
)) +
  scale_y_continuous(expand = expansion(mult = c(0, 0.12))) +  #ajusta el eje Y para que las etiquetas quepan sin cortarse
  labs(title = "Comparendos por tipo de titular", x = NULL, y = "Comparendos", fill = NULL)  #agrega titulo y nombres a los ejes (x=NULL oculta el titulo del eje X)

Las personas naturales concentran 77,7 % de los comparendos y las empresas el 22,3 % restante. Dentro de las personas naturales, las mujeres aparecen más que los hombres; sin embargo, la base no trae el número de mujeres y hombres conductores, así que no se puede afirmar que ellas infrinjan más, solo que a su nombre hay más comparendos.

¿Cambia el tipo de vehículo según el titular?

veh <- comp %>%  #crea un nuevo objeto llamado veh con los datos de comp
  count(sexo, vehiculo) %>%  #cuenta las filas agrupando por sexo y tipo de vehiculo, genera columnas: sexo, vehiculo, n
  group_by(sexo) %>%  #agrupa por sexo para que los calculos siguientes se hagan dentro de cada grupo (natural/juridica)
  mutate(porcentaje = 100 * n / sum(n)) %>%  #calcula el porcentaje de cada vehiculo dentro de su grupo de sexo (no del total general)
  ungroup()  #elimina la agrupacion para evitar comportamientos inesperados en pasos siguientes

veh %>%  #toma la tabla veh y la pasa a la siguiente funcion
  filter(vehiculo == "MOTO") %>%  #filtra dejando solo las filas donde el vehiculo es "MOTO"
  select(sexo, motos = n, `% de sus comparendos en moto` = porcentaje) %>%  #selecciona y renombra columnas: sexo, n pasa a llamarse motos, porcentaje pasa a llamarse % de sus comparendos en moto
  kable(digits = 1)  #muestra la tabla en formato HTML con 1 decimal
sexo motos % de sus comparendos en moto
CÉDULA NUEVA 7 8.0
EMPRESA 17 3.6
HOMBRE 89 14.5
MUJER 69 7.3
ggplot(veh, aes(x = sexo, y = porcentaje, fill = vehiculo)) +  #inicia grafico: sexo en eje X, porcentaje en eje Y, barras coloreadas por tipo de vehiculo
  geom_col() +  #agrega barras verticales apiladas
  scale_fill_manual(values = c(  #asigna colores manuales a cada tipo de vehiculo
  "CARRO" = "#2C3E50",  #azul oscuro para carro
  "MOTO" = "#1ABC9C"  #verde turquesa para moto
)) +
  labs(title = "          Distribución del tipo de vehículo según el titular",  #agrega titulo (los espacios al inicio lo centran visualmente)
       x = NULL, y = "% de los comparendos", fill = "Vehículo")  #oculta titulo del eje X, nombra eje Y y leyenda

En todos los grupos predomina el carro. La moto pesa más entre los hombres (14,5 %) que entre las mujeres (7,3 %) y las empresas (3,6 %).

¿Qué infracciones se cometen y cuánto representan?

inf <- comp %>%  #crea un nuevo objeto llamado inf con los datos de comp
  group_by(infraccion) %>%  #agrupa por tipo de infraccion para que los calculos se hagan por cada categoria
  summarise(comparendos = n(), total = sum(valor)) %>%  #resume cada grupo: n() cuenta los comparendos, sum(valor) suma el monto total a pagar
  arrange(desc(comparendos)) %>%  #ordena las filas de mayor a menor segun la cantidad de comparendos
  mutate(pct = 100 * comparendos / sum(comparendos),  #calcula el porcentaje de cada infraccion sobre el total de comparendos
         pct_acumulado = cumsum(pct))  #cumsum() suma los porcentajes de forma acumulada (primer valor + segundo + tercero...)

kable(inf, digits = 1, format.args = list(big.mark = ","),  #muestra la tabla en HTML con 1 decimal y comas en los miles (ej: 1,234)
      col.names = c("Infracción", "Comparendos", "Total a pagar", "% del total", "% acumulado"))  #renombra las columnas de la tabla
Infracción Comparendos Total a pagar % del total % acumulado
Exceso de velocidad 1,626 713,651,400 76.7 76.7
Omitir luz roja o PARE 385 168,976,500 18.2 94.9
Detenerse sobre la cebra 105 46,084,500 5.0 99.8
Transitar en sentido contrario 4 1,755,600 0.2 100.0
ggplot(inf, aes(x = reorder(infraccion, -comparendos), y = pct, fill = infraccion)) +  #inicia grafico: reorder ordena las barras de mayor a menor (el - invierte), fill colorea por infraccion
  geom_col() +  #agrega barras verticales
  geom_text(aes(label = pct(pct)),  #agrega etiquetas de texto con el porcentaje formateado
          size = 4.5,            # tamaño de la letra
          fontface = "bold",     # negrita
          color = "black",       # color del texto
          vjust = -0.7) +         # desplaza la etiqueta hacia arriba de la barra

 scale_fill_manual(values = c(  #asigna colores manuales a cada tipo de infraccion
  "Exceso de velocidad" = "#346B82",  #azul
    "Omitir luz roja o PARE" = "#D4A35A",  #dorado
      "Detenerse sobre la cebra" = "#78A69A",  #verde
        "Transitar en sentido contrario" = "#C77D68"  #naranja
)) +
  
  labs(title = "        Porcentaje de cada infracción en el total de comparendos",  #agrega titulo (espacios para centrar visualmente)
       x = NULL, y = NULL) +  #oculta los titulos de ambos ejes
  
  scale_y_continuous(expand = expansion(mult = c(0.025, 0.10))) +  #agrega espacio arriba (10%) y abajo (2.5%) del eje Y para que las etiquetas no se corten
  
  theme(  #personaliza la apariencia del grafico
  panel.grid.major.x = element_blank(),  #elimina las lineas de cuadricula verticales
  panel.grid.minor = element_blank(),  #elimina las lineas de cuadricula menores
  axis.text.x = element_text(  #personaliza el texto del eje X
    size = 9,  #tamano de letra
    face = "bold",  #negrita
    color = "black"  #color negro
  ),
  plot.title = element_text(  #personaliza el titulo del grafico
    face = "bold",  #negrita
    color = "black",  #color negro
    hjust = 0.5  #centra el titulo horizontalmente
  ),
  legend.position = "none"  #elimina la leyenda (ya que cada barra tiene su propia etiqueta)
)

Como todos los comparendos valen lo mismo, el porcentaje de dinero coincide con el de casos. Exceso de velocidad representa 76,7 % de los comparendos y, sumada a Omitir luz roja o PARE, llega a 94,9 %. Esto significa que el recaudo depende casi por completo de dos conductas; las otras dos infracciones son poco frecuentes.

¿Cuándo ocurren?

Evolución semana a semana

comp %>%  #toma el data.frame comp y lo pasa a la siguiente funcion
  count(semana_txt, dia_sem) %>%  #cuenta las filas agrupando por semana y dia de la semana, genera columnas: semana_txt, dia_sem, n
  ggplot(aes(x = dia_sem, y = semana_txt, fill = n)) +  #inicia grafico: dias en eje X, semanas en eje Y, el color de relleno depende de la cantidad n
  geom_tile(color = "white") +  #dibuja los cuadros del heatmap con borde blanco para separar cada celda
  geom_text(  #agrega el numero de comparendos dentro de cada celda
  aes(label = n, color = n > 55),  #label muestra el valor de n, color cambia segun si n es mayor a 55 (para que el texto se lea bien sobre fondos oscuros)
  size = 3.2,  #tamano de la letra
  fontface = "bold"  #negrita
) +
scale_color_manual(  #define los colores del texto segun la condicion n > 55
  values = c("FALSE" = "#2C3E50", "TRUE" = "#FFFFFF"),  #si n <= 55 texto azul oscuro, si n > 55 texto blanco
  guide = "none"  #oculta la leyenda del color del texto
)+
  scale_fill_gradientn(  #define la escala de colores del relleno de las celdas (de menor a mayor cantidad)
  colours = c(
    "#EDE9F6",  #morado muy claro (pocos comparendos)
    "#A99ACB",  #morado medio
    "#514A86"   #morado oscuro (muchos comparendos)
  )
) +
  labs(title = "Comparendos por día de la semana y semana del año",  #agrega titulo al grafico
       x = NULL, y = "Semana (lunes de inicio, dd/mm)", fill = "Comparendos")  #oculta titulo del eje X, nombra eje Y y leyenda de color

Promedio por día de la semana

por_dia <- comp %>%  #crea un nuevo objeto llamado por_dia con los datos de comp
  count(fecha, dia_sem) %>%  #cuenta las filas agrupando por fecha y dia de la semana, genera columnas: fecha, dia_sem, n
  group_by(dia_sem) %>%  #agrupa por dia de la semana para que los calculos se hagan por cada dia (lunes, martes, etc.)
  summarise(dias_en_periodo = n(), comparendos = sum(n), promedio_diario = round(mean(n), 1))  #resume cada grupo: n() cuenta cuantas fechas distintas hay de ese dia, sum(n) suma los comparendos totales, round(mean(n), 1) calcula el promedio diario redondeado a 1 decimal

kable(por_dia, col.names = c("Día", "Días en el periodo", "Comparendos", "Promedio por día"))  #muestra la tabla en HTML renombrando las columnas
Día Días en el periodo Comparendos Promedio por día
Lunes 7 295 42.1
Martes 7 264 37.7
Miércoles 7 273 39.0
Jueves 7 256 36.6
Viernes 6 264 44.0
Sábado 6 372 62.0
Domingo 6 396 66.0
pico <- comp %>% count(fecha) %>% slice_max(n, n = 1)  #cuenta comparendos por fecha y slice_max() extrae la fila con el valor maximo de n (el dia con mas comparendos), n=1 indica que solo queremos 1 resultado

Al comparar promedios (y no totales, porque cada día de la semana aparece un número distinto de veces en el periodo), el día más cargado es el Domingo, con 66 comparendos por día en promedio. El máximo diario ocurrió el 01/05/2010, con 89 comparendos, y la actividad cae en la última semana del periodo, lo que podría deberse a cierres de registro o a cambios en los operativos (hipótesis que requiere confirmar con la entidad).

Abril contra mayo

comp %>%  #toma el data.frame comp y lo pasa a la siguiente funcion
  mutate(mes = if_else(format(fecha, "%m") == "04", "Abril", "Mayo")) %>%  #crea columna mes: format(fecha, "%m") extrae el numero del mes como texto, if_else evalua si es "04" asigna "Abril", de lo contrario asigna "Mayo"
  group_by(mes) %>%  #agrupa por mes para que los calculos se hagan por cada mes
  summarise(comparendos = n(), dias_con_datos = n_distinct(fecha),  #resume cada grupo: n() cuenta el total de comparendos, n_distinct(fecha) cuenta cuantos dias distintos tienen datos
            promedio_diario = round(n() / n_distinct(fecha), 1)) %>%  #calcula el promedio dividiendo total de comparendos entre dias con datos, redondeado a 1 decimal
  kable(col.names = c("Mes", "Comparendos", "Días con datos", "Promedio por día"))  #muestra la tabla en HTML renombrando las columnas
Mes Comparendos Días con datos Promedio por día
Abril 712 19 37.5
Mayo 1408 27 52.1

Mayo tiene casi el doble de comparendos que abril, pero buena parte de esa diferencia se explica porque abril solo tiene datos desde el día 12. Por día, el aumento es bastante menor.

¿Cuántas veces se repiten?

por_ejecutado <- comp %>% count(id, name = "n_comp")  #cuenta cuantos comparendos tiene cada id (persona/empresa) y guarda el resultado en la columna n_comp en lugar de la columna n por defecto

grupos <- por_ejecutado %>%  #crea un nuevo objeto llamado grupos
  mutate(grupo = case_when(n_comp == 1 ~ "1 comparendo",  #clasifica cada persona/empresa segun su cantidad de comparendos:
                           n_comp == 2 ~ "2 comparendos",  #si tiene 2
                           n_comp <= 4 ~ "3 a 4",          #si tiene entre 3 y 4
                           TRUE ~ "5 o más"),              #si tiene 5 o mas
         grupo = factor(grupo, levels = c("1 comparendo", "2 comparendos", "3 a 4", "5 o más"))) %>%  #convierte grupo en factor con un orden fijo para que las barras del grafico salgan en ese orden
  group_by(grupo) %>%  #agrupa por grupo para los calculos siguientes
  summarise(ejecutados = n(), comparendos = sum(n_comp)) %>%  #resume: n() cuenta cuantas personas/empresas hay en cada grupo, sum(n_comp) suma sus comparendos totales
  mutate(pct_ejecutados = 100 * ejecutados / sum(ejecutados),  #calcula el porcentaje de personas/empresas de cada grupo sobre el total
         pct_comparendos = 100 * comparendos / sum(comparendos))  #calcula el porcentaje de comparendos de cada grupo sobre el total

kable(grupos, digits = 1, col.names = c("Grupo", "Personas/empresas", "Comparendos", "% de personas/empresas", "% de comparendos"))  #muestra la tabla en HTML con 1 decimal y columnas renombradas
Grupo Personas/empresas Comparendos % de personas/empresas % de comparendos
1 comparendo 894 894 71.5 42.2
2 comparendos 198 396 15.8 18.7
3 a 4 116 383 9.3 18.1
5 o más 43 447 3.4 21.1
bind_rows(  #apila dos tablas una debajo de la otra (una fila por cada combinacion de grupo y medida)
  grupos %>% transmute(grupo, medida = "% de personas/empresas", valor = pct_ejecutados),  #primera tabla: extrae grupo y el porcentaje de personas/empresas
  grupos %>% transmute(grupo, medida = "% de comparendos", valor = pct_comparendos)  #segunda tabla: extrae grupo y el porcentaje de comparendos
) %>%
  ggplot(aes(x = grupo, y = valor, fill = medida)) +  #inicia grafico: grupos en eje X, valor en eje Y, color por tipo de medida
  geom_col(position = "dodge") +  #agrega barras lado a lado (no apiladas) gracias a position = "dodge"
  geom_text(aes(label = pct(valor)), position = position_dodge(width = 0.9), vjust = -0.4, size = 3.3) +  #agrega etiquetas de porcentaje sobre cada barra, position_dodge las alinea con su barra correspondiente
  scale_fill_manual(values = c("#78A69A", "#346B82")) +  #asigna colores manuales a las dos medidas
  scale_y_continuous(expand = expansion(mult = c(0, 0.12))) +  #agrega espacio arriba del eje Y para que las etiquetas no se corten
  labs(title = "Quiénes se repiten y cuánto pesan en el total", x = NULL, y = NULL, fill = NULL)  #agrega titulo y oculta titulos de ejes y leyenda

n_reinc    <- sum(por_ejecutado$n_comp >= 2)  #cuenta cuantas personas/empresas tienen 2 o mas comparendos (reincidentes)
comp_reinc <- sum(por_ejecutado$n_comp[por_ejecutado$n_comp >= 2])  #suma los comparendos totales que pertenecen a los reincidentes

Hay 357 personas o empresas con dos o más comparendos (28,5 % de las 1.251 que aparecen), y entre todas acumulan 1.226 comparendos, es decir 57,8 % del total. Es el hallazgo más importante del informe: una minoría de titulares explica más de la mitad de los comparendos.

Los casos extremos

# Personas naturales con más comparendos (con nombre)
comp %>%  #toma el data.frame comp y lo pasa a la siguiente funcion
  filter(persona == "Persona natural") %>%  #filtra dejando solo las filas donde persona es "Persona natural"
  count(ejecutado, name = "comparendos", sort = TRUE) %>%  #cuenta comparendos por titular, name renombra la columna n a "comparendos", sort=TRUE ordena de mayor a menor automaticamente
  head(5) %>%  #se queda solo con las primeras 5 filas (los 5 con mas comparendos)
  kable(col.names = c("Titular", "Comparendos"))  #muestra la tabla en HTML renombrando las columnas
Titular Comparendos
LILIANA ROZO PINZON 27
ELVIRA DEL CARMEN GARRIDO AREVALO 10
MIGUEL HERNANDO GARAY CALLE 9
IRIS DEL CARMEN OVIEDO CANTILLO 8
JOSE ANTONIO TOVAR PUCCINI 8
# Empresas con más comparendos
top_emp <- comp %>%  #crea un nuevo objeto llamado top_emp
  filter(persona == "Persona jurídica") %>%  #filtra dejando solo las filas donde persona es "Persona jurídica"
  group_by(ejecutado) %>%  #agrupa por nombre de la empresa
  summarise(comparendos = n(), total = sum(valor)) %>%  #resume: n() cuenta los comparendos, sum(valor) suma el monto total a pagar por cada empresa
  arrange(desc(comparendos)) %>%  #ordena de mayor a menor segun la cantidad de comparendos
  head(5)  #se queda solo con las primeras 5 filas (las 5 empresas con mas comparendos)

kable(top_emp, format.args = list(big.mark = ","),  #muestra la tabla en HTML con comas en los miles (ej: 1,234,567)
      col.names = c("Empresa", "Comparendos", "Total a pagar"))  #renombra las columnas de la tabla
Empresa Comparendos Total a pagar
LEASING DE CREDITO SA 110 48,279,000
TRANSPORTES MST Y CIA S. EN C 48 21,067,200
FINANCIERA INTERNACIONAL S.A 32 14,044,800
GMAC FINANCIERA DE COLOMBI 21 9,216,900
UINON FAMILIAR CHARRIS S.EN C 13 5,705,700

Una sola empresa acumula más comparendos que cualquier persona natural. LEASING DE CREDITO SA suma 110 comparendos ($48.279.000 a pagar), lo que equivale a 23,3 % de los comparendos de empresas y 5,2 % del total. Las cinco empresas con más comparendos reúnen 224 casos ($98.313.600), es decir, 47,5 % de los comparendos de empresas y 10,6 % del total.

Reincidencia por vehículo

por_placa <- comp %>% count(placa, name = "n_comp")  #cuenta cuantos comparendos tiene cada placa y guarda el resultado en la columna n_comp
placas_rep <- sum(por_placa$n_comp > 1)  #cuenta cuantas placas tienen mas de 1 comparendo (placas repetidas)

# Tabla 1: cuántas placas tienen 1, 2, 3-4 o 5+ comparendos
tabla_placas <- por_placa %>%  #crea un nuevo objeto llamado tabla_placas
  mutate(grupo = case_when(n_comp == 1 ~ "1 Comparendo",  #clasifica cada placa segun su cantidad de comparendos:
                           n_comp == 2 ~ "2 Comparendos",  #si tiene 2
                           n_comp <= 4 ~ "3 a 4",          #si tiene entre 3 y 4
                           TRUE ~ "5 o Más"),              #si tiene 5 o mas
         grupo = factor(grupo, levels = c("1 Comparendo", "2 Comparendos", "3 a 4", "5 o Más"))) %>%  #convierte grupo en factor con orden fijo para tablas y graficos
  group_by(grupo) %>%  #agrupa por grupo para los calculos siguientes
  summarise(placas = n(), comparendos = sum(n_comp)) %>%  #resume: n() cuenta cuantas placas hay en cada grupo, sum(n_comp) suma sus comparendos totales
  mutate(pct_placas = 100 * placas / sum(placas),  #calcula el porcentaje de placas de cada grupo sobre el total
         pct_comparendos = 100 * comparendos / sum(comparendos))  #calcula el porcentaje de comparendos de cada grupo sobre el total

kable(tabla_placas, digits = 1,  #muestra la tabla en HTML con 1 decimal
      col.names = c("Grupo", "Placas", "Comparendos", "% de placas", "% de comparendos"))  #renombra las columnas de la tabla
Grupo Placas Comparendos % de placas % de comparendos
1 Comparendo 1074 1074 73.7 50.7
2 Comparendos 242 484 16.6 22.8
3 a 4 109 363 7.5 17.1
5 o Más 32 199 2.2 9.4
# Tabla 2: las 5 placas con más comparendos
comp %>%  #toma el data.frame comp y lo pasa a la siguiente funcion
  group_by(placa, vehiculo, sexo) %>%  #agrupa por placa, tipo de vehiculo y sexo del titular
  summarise(comparendos = n(), total = sum(valor), .groups = "drop") %>%  #resume: n() cuenta comparendos, sum(valor) suma el monto total, .groups="drop" elimina la agrupacion al finalizar
  arrange(desc(comparendos)) %>%  #ordena de mayor a menor segun la cantidad de comparendos
  head(5) %>%  #se queda solo con las primeras 5 filas (las 5 placas con mas comparendos)
  select(sexo, placa, vehiculo, comparendos, total) %>%  #reordena las columnas para que coincidan con el orden de col.names en kable
  kable(format.args = list(big.mark = ","),  #muestra la tabla en HTML con comas en los miles
        col.names = c("Sexo del titular","Placa", "Vehículo", "Comparendos", "Total a pagar"))  #renombra las columnas de la tabla
Sexo del titular Placa Vehículo Comparendos Total a pagar
MUJER UZD320 CARRO 10 4,389,000
HOMBRE BSB95A MOTO 9 3,950,100
EMPRESA UYU455 CARRO 9 3,950,100
EMPRESA QHT304 CARRO 8 3,511,200
MUJER UYW049 CARRO 8 3,511,200

De las 1.457 placas distintas, 383 (26,3 %) tienen más de un comparendo, y esas placas reúnen 1.046 comparendos (49,3 % del total). El vehículo con más registros acumula 10.

Conclusiones y recomendaciones

  1. La reincidencia es el eje del problema. Menos de un tercio de los titulares concentra más de la mitad de los comparendos, por lo que las medidas dirigidas a reincidentes (cursos obligatorios, seguimiento, sanciones progresivas) tendrían más efecto que las campañas generales.
  2. Dos infracciones sostienen casi todo el recaudo: el exceso de velocidad y omitir luz roja o PARE. Reforzar la señalización y los controles en esos puntos sería lo más rentable.
  3. Las empresas necesitan un tratamiento propio. Tienen un peso importante y, en algunos casos, un volumen muy superior al de cualquier persona natural; conviene identificar quién conduce realmente los vehículos de las empresas de leasing.
  4. Los datos necesitan depuración antes de usarlos para decidir: comparendos repetidos, la categoría “cédula nueva” en SEXO, la fecha invertida en la columna FECHA, y la ausencia del nombre de la infracción.
  5. Limitación del análisis: como la base solo cubre 46 días, no permite hablar de tendencias ni de estacionalidad; es una fotografía de un periodo corto.

Referencias

Secretaría de Tránsito de Barranquilla. Base de datos de comparendos 2010 (archivo BD_Comparendos_OK .xlsx).