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:
- ¿Quién recibe los comparendos (personas naturales o empresas)?
- ¿Qué infracciones se cometen y cuánto representan en dinero?
- ¿Cuándo ocurren (día de la semana y evolución por semanas)?
- ¿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 leyendaEn 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 colorPromedio 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 resultadoAl 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 leyendan_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 reincidentesHay 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
- 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.
- 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.
- 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.
- 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 columnaFECHA, y la ausencia del nombre de la infracción. - 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).