Una mirada a las infracciones de tránsito, su frecuencia, impacto económico y comportamiento en el tiempo.
Objetivo
Este informe aplica herramientas estadísticas básicas en R al análisis de los comparendos de tránsito impuestos en Barranquilla entre el 12/04/2010 y el 27/05/2010. Se exploran, describen y visualizan los datos para identificar patrones, tendencias y relaciones relevantes, mediante medidas de frecuencia, concentración y evolución en el tiempo, que apoyen la toma de decisiones en la gestión del tránsito.
Pasa el cursor sobre cualquier gráfico para leer sus datos exactos. Cada gráfico se dibuja al llegar a él, y el botón «↻ Repetir» lo anima de nuevo. El botón «Ocultar código» (arriba a la derecha) muestra u oculta el código en R de todo el informe.
Indicadores
La base tiene buena integridad (0 valores vacíos), pero se detectaron 1 fila duplicada exacta y 17 números de comparendo repetidos con distinto mandamiento. Fueron depurados o señalados para garantizar la calidad del análisis.
Descripción general
La base reúne comparendos aplicados a conductores y propietarios de vehículos en Barranquilla (Atlántico). Cada registro incluye datos del infractor (nombre, género, tipo y número de identificación), del vehículo (placa y tipo), de la infracción (código y nombre), la fecha del comparendo desglosada en día, mes y año, y el valor a pagar. En total tiene 25 columnas y 2.120 registros originales (2.119 tras la depuración), lo que permite un análisis estadístico descriptivo sólido.
Origen y estructura
La información proviene de la base de comparendos de tránsito con 25 variables originales sobre el infractor, la infracción, la fecha, el vehículo y el valor económico del comparendo. A continuación se muestra el código con el que se leyó y depuró la base.
# Lectura y depuración de la base
raw <- read_excel(ruta, sheet = "BD Comparendos OK")
n_raw <- nrow(raw)
datos <- raw %>% select(-starts_with("#")) %>% distinct() %>% janitor::clean_names()
n_dup <- n_raw - nrow(datos)
datos <- datos %>% mutate(
ejecutado = ejecutado %>% str_squish() %>% str_replace_all("G\\.M\\.A\\.C\\.", "GMAC"),
tipo_id = recode(tipo_de_identificacion, "Cedula de Ciudadanía" = "Cédula de ciudadanía",
"Cedula de Extanjería" = "Cédula de extranjería", "Nit" = "NIT"),
infraccion = str_to_sentence(nom_infraccion) %>% str_replace("maxima", "máxima"),
fecha = as.Date(fecha_de_comparendo),
smlv = costo_de_comparendo / smlv_2010,
dia = factor(str_to_title(nom_dia), levels = c("Lunes","Martes","Miércoles","Jueves","Viernes","Sábado","Domingo")),
mes = factor(str_to_title(nom_mes), levels = c("Abril", "Mayo")),
vehiculo = str_to_title(vehiculo))
# Resumen de la base y variables principales
resumen <- tibble(Indicador = c("Registros (base depurada)", "Columnas originales", "Valores vacíos", "Filas duplicadas exactas",
"Comparendos únicos", "Propietarios únicos", "Placas únicas", "Período"),
Valor = c(fm(nrow(datos)), ncol(raw), sum(is.na(raw)), n_dup, fm(n_distinct(datos$comparendo)),
fm(n_distinct(datos$ejecutado)), fm(n_distinct(datos$placa_de_vehiculo)), paste(f_ini, "a", f_fin)))
vars <- c("Tipo de vehículo", "Infracción", "Fecha del comparendo", "Valor del comparendo (COP y SMLV)", "Tipo de identificación", "Propietario (ejecutado)", "Género")
salida('<div class="dos-col">', tabla_html(resumen), '<div class="vars" id="o2"><b>Variables principales</b><ul>', paste0("<li>", vars, "</li>", collapse = ""), '</ul></div></div>')
| Indicador | Valor |
|---|---|
| Registros (base depurada) | 2.119 |
| Columnas originales | 25 |
| Valores vacíos | 0 |
| Filas duplicadas exactas | 1 |
| Comparendos únicos | 2.102 |
| Propietarios únicos | 1.247 |
| Placas únicas | 1.457 |
| Período | 12/04/2010 a 27/05/2010 |
Se eliminó 1 fila duplicada, se unificaron nombres (p. ej. G.M.A.C. por GMAC), se corrigieron etiquetas y se convirtió el valor a SMLV de 2010 ($ 515.000). Cada comparendo vale 0,1, 0,5 o 1 SMLV.
Aplicación de funciones: colnames()
Lo primero es identificar los nombres de las columnas para poder llamarlas correctamente en el análisis.
# Nombres de las columnas originales
cat(paste0('<span class="tag">', str_squish(colnames(raw)), '</span>', collapse = ""))
No. MANDAMIENTO DE PAGOFECHA MANDAMIENTO DE PAGOEJECUTADOTIPO DE IDENTIFICACIONNo. IDENTIFICACION#TIPO DE IDENTIFICACIONGENERO# GENEROCOD. INFRACCION# COD. INFRACCIONNOM.INFRACCION#NOM. INFRACCIONCOMPARENDOFECHA DE COMPARENDOAÑOMESNOM MES# NOM. MESDIANOM DIA# NOM. DiaPLACA DE VEHICULOVEHICULO#VEHICULOCOSTO DE COMPARENDO
Aplicación de funciones: resumen estadístico
Resumen general de la fecha y del valor a pagar, para revisar la distribución y los cuartiles.
# Resumen estadístico (mínimo, cuartiles, mediana, media y máximo)
fq <- as.numeric(datos$fecha); vq <- datos$costo_de_comparendo
est <- tibble(`Estadístico` = c("Mínimo", "1.er cuartil", "Mediana", "Media", "3.er cuartil", "Máximo"),
`Fecha del comparendo` = format(as.Date(unname(c(min(fq), quantile(fq, .25), median(fq), mean(fq), quantile(fq, .75), max(fq))), origin = "1970-01-01"), "%d/%m/%Y"),
`Valor del comparendo` = cop(unname(c(min(vq), quantile(vq, .25), median(vq), mean(vq), quantile(vq, .75), max(vq)))))
salida(tabla_html(est))
| Estadístico | Fecha del comparendo | Valor del comparendo |
|---|---|---|
| Mínimo | 12/04/2010 | $ 51.500 |
| 1.er cuartil | 27/04/2010 | $ 257.500 |
| Mediana | 06/05/2010 | $ 257.500 |
| Media | 05/05/2010 | $ 303.775 |
| 3.er cuartil | 16/05/2010 | $ 257.500 |
| Máximo | 27/05/2010 | $ 515.000 |
3.1 Comparendos por día de la semana y tipo de vehículo
Qué muestra: cuántos comparendos se impusieron cada día de la semana, separados entre autos (azul) y motos (coral).
Cómo leerlo: cada columna es un día; su altura es el total de comparendos y el número en negrita sobre ella es ese total. La parte azul de la columna son los autos y la coral las motos.
Al pasar el cursor: al situarte sobre un día aparece el detalle de autos, motos y el total de ese día.
Para qué sirve: identificar los días con más infracciones para programar operativos de control en esos momentos.
# Barras apiladas por día (autos y motos) con el total encima
d_dia <- datos %>% count(dia, vehiculo) %>%
mutate(dia = as.character(dia), tip = paste0(vehiculo, ": ", fm(n), " comparendos"))
tot_dia <- datos %>% count(dia) %>%
mutate(dia = as.character(dia), tip = paste0("<b>Total: ", fm(n), " comparendos</b>"))
p <- plot_ly(height = 460)
for (veh in names(col_veh)) {
p <- add_bars(p, data = filter(d_dia, vehiculo == veh), x = ~dia, y = ~n, name = veh,
marker = list(color = col_veh[[veh]]), hoverinfo = "text", hovertext = ~tip)
}
p <- p %>%
add_trace(data = tot_dia, x = ~dia, y = ~n, type = "scatter", mode = "text", text = ~fm(n),
textposition = "top center", textfont = list(size = 15, color = pal$marino),
showlegend = FALSE, hoverinfo = "text", hovertext = ~tip) %>%
layout(barmode = "stack", hovermode = "x unified",
xaxis = eje_cat(levels(datos$dia)), yaxis = eje_val(max(tot_dia$n) * 1.18)) %>%
pl("Comparendos por día de la semana")
graf(p)
Sábado y domingo concentran el 36,2% de los comparendos; el día con más registros es el domingo (396). Los autos representan el 91,4% del total.
3.2 Evolución diaria de los comparendos
La variación diaria permite detectar días atípicos, eventos especiales o aumentos asociados a operativos específicos, clima, festivos o tráfico inusual. El patrón temporal sirve para prever puntos críticos y ajustar los operativos de tránsito.
Qué muestra: el número de comparendos de cada fecha entre abril y mayo, como una línea con el área sombreada debajo.
Cómo leerlo: el eje horizontal son las fechas (una marca por semana) y el vertical la cantidad de comparendos de ese día. Los tres puntos coral con número son los días con más registros.
Al pasar el cursor: sobre cualquier punto de la línea aparecen la fecha, el día de la semana y los comparendos de ese día.
Para qué sirve: ver en qué fechas se disparan las infracciones y reconocer días atípicos, como operativos, festivos o puentes.
# Línea con área y los 3 días pico resaltados
diario <- datos %>% count(fecha, dia) %>%
mutate(tip = paste0("<b>", dia, " ", format(fecha, "%d/%m/%Y"), "</b><br>", fm(n), " comparendos"))
picos <- diario %>% slice_max(n, n = 3, with_ties = FALSE)
p <- plot_ly(height = 440) %>%
add_trace(data = diario, x = ~fecha, y = ~n, type = "scatter", mode = "lines+markers",
fill = "tozeroy", fillcolor = "rgba(20,184,166,.20)", name = "Comparendos",
line = list(color = pal$turquesa, width = 3), marker = list(color = pal$turquesa, size = 6),
hoverinfo = "text", hovertext = ~tip) %>%
add_trace(data = picos, x = ~fecha, y = ~n, type = "scatter", mode = "markers+text", name = "Días pico",
text = ~n, textposition = "top center", textfont = list(color = pal$coral, size = 15),
marker = list(color = pal$coral, size = 13, line = list(color = "white", width = 2)),
hoverinfo = "text", hovertext = ~tip) %>%
layout(xaxis = list(title = "", type = "date", tickformat = "%d/%m", dtick = 7 * 24 * 3600 * 1000,
tick0 = as.character(min(diario$fecha)), gridcolor = "#E5EAF2", fixedrange = TRUE),
yaxis = eje_val(max(diario$n) * 1.25)) %>%
pl("Comparendos por fecha de infracción")
graf(p)
3.3 Comparendos por género o tipo de titular
Se cuenta la cantidad de comparendos según el género del infractor o si el titular es una empresa.
Qué muestra: cuántos comparendos corresponden a mujeres, hombres, empresas y cédulas nuevas.
Cómo leerlo: cada columna es una categoría; encima aparece la cantidad de comparendos y, entre paréntesis, el porcentaje que representa del total. Las columnas van de la más alta a la más baja.
Al pasar el cursor: sobre una columna aparecen la categoría, la cantidad y su porcentaje del total.
Para qué sirve: saber quién concentra las infracciones y si conviene diferenciar las estrategias entre personas naturales y empresas.
# Barras por género con cantidad y porcentaje
gen <- datos %>% count(genero = str_to_title(genero)) %>% mutate(p = n / sum(n)) %>% arrange(desc(n)) %>%
mutate(txt = paste0(fm(n), "<br>(", pct(p), ")"),
tip = paste0("<b>", genero, "</b><br>", fm(n), " comparendos<br>", pct(p), " del total"),
col = unname(col_gen[genero]))
p <- plot_ly(gen, x = ~genero, y = ~n, type = "bar", marker = list(color = gen$col),
text = ~txt, textposition = "outside", cliponaxis = FALSE,
textfont = list(size = 15, color = pal$marino),
hoverinfo = "text", hovertext = ~tip, height = 440) %>%
layout(xaxis = eje_cat(gen$genero), yaxis = eje_val(max(gen$n) * 1.3)) %>%
pl("Distribución de comparendos por género o empresa", leyenda = FALSE)
graf(p)
La categoría con más comparendos es «Mujer» (45,7%). Las empresas aportan el 22,0% de los comparendos, lo que indica la necesidad de fortalecer el control sobre las flotas vehiculares corporativas y de diferenciar las estrategias entre personas naturales y jurídicas.
3.4 Valor económico por tipo de infracción
Se suman los valores de los comparendos agrupados por la infracción cometida. Es el valor impuesto, no el recaudo efectivo, porque la base no trae fechas de pago.
Qué muestra: cuánto dinero suman los comparendos de cada tipo de infracción.
Cómo leerlo: cada barra horizontal es una infracción y su longitud es el valor total en pesos. A la derecha se ve el monto y, entre paréntesis, el porcentaje del valor total. Van ordenadas de mayor a menor.
Al pasar el cursor: sobre una barra aparecen el nombre completo de la infracción, su valor, su participación y el número de comparendos.
Para qué sirve: priorizar las infracciones que más pesan en el valor total, que no siempre son las más frecuentes.
# Barras horizontales del valor económico por infracción
inf_v <- datos %>% group_by(infraccion) %>% summarise(v = sum(costo_de_comparendo), n = n(), .groups = "drop") %>%
arrange(desc(v)) %>% mutate(p = v / sum(v))
inf_g <- inf_v %>% arrange(v) %>%
mutate(et = wrapbr(infraccion, 28), txt = paste0(cop(v), " (", pct(p), ")"),
tip = paste0("<b>", infraccion, "</b><br>Valor: ", cop(v), "<br>Participación: ", pct(p), "<br>Comparendos: ", fm(n)))
p <- plot_ly(inf_g, x = ~v, y = ~et, type = "bar", orientation = "h", marker = list(color = pal$coral),
text = ~txt, textposition = "outside", cliponaxis = FALSE,
textfont = list(size = 14, color = pal$marino),
hoverinfo = "text", hovertext = ~tip, height = 430) %>%
layout(xaxis = eje_val(max(inf_g$v) * 1.65, showticklabels = FALSE, showgrid = FALSE),
yaxis = eje_cat(inf_g$et)) %>%
pl("Valor económico de los comparendos por infracción", leyenda = FALSE)
graf(p)
«Velocidad superior a la máxima permitida» aporta $ 418.695.000 (65,0%), lo que indica alta frecuencia y sanción elevada. Le sigue «No detenerse ante una luz roja o amarilla» con $ 197.760.000. Entre las dos suman el 95,8% del valor total; «Transitar en sentido contrario» tiene un valor mínimo, por su baja ocurrencia o menor detección.
3.5 Comparendos por mes
Se agrupan los comparendos por el mes en que ocurrieron para revisar la variación mensual.
Qué muestra: el total de comparendos de abril y de mayo.
Cómo leerlo: la altura de cada columna es el total del mes; encima aparece ese total y el promedio de comparendos por día. Abril empieza el 12/04, así que tiene menos días y conviene comparar con el promedio diario, no con el total.
Al pasar el cursor: sobre una columna aparecen el total, los días con registros, el promedio diario y el valor del mes.
Para qué sirve: comparar los dos meses de forma justa y ver si la actividad aumentó o bajó.
# Barras de comparendos por mes con promedio diario
mes_t <- datos %>% group_by(mes) %>% summarise(n = n(), dias = n_distinct(fecha), v = sum(costo_de_comparendo), .groups = "drop") %>%
mutate(prom = n / dias, mes = as.character(mes),
txt = paste0("<b>", fm(n), " comparendos</b><br>", format(round(prom, 1), decimal.mark = ","), " por día"),
tip = paste0("<b>", mes, "</b><br>", fm(n), " comparendos<br>", dias, " días con registros<br>",
format(round(prom, 1), decimal.mark = ","), " por día<br>Valor: ", cop(v)))
p <- plot_ly(mes_t, x = ~mes, y = ~n, type = "bar",
marker = list(color = unname(c(Abril = pal$azul, Mayo = pal$turquesa)[mes_t$mes])),
text = ~txt, textposition = "outside", cliponaxis = FALSE, textfont = list(size = 15, color = pal$marino),
hoverinfo = "text", hovertext = ~tip, height = 430) %>%
layout(xaxis = eje_cat(mes_t$mes), yaxis = eje_val(max(mes_t$n) * 1.3), bargap = 0.5) %>%
pl("Comparendos por mes", leyenda = FALSE)
graf(p)
Mayo registra 1.408 comparendos frente a 711 de abril (98% más). Pero abril solo cubre 19 días (desde el 12/04/2010) y mayo 27, así que la comparación justa es el promedio diario: 37,4 frente a 52,1 (39% más).
3.6 Personas naturales con más comparendos
Se identifican las 10 personas con más comparendos registrados, excluyendo empresas (se incluyen los empates en el último lugar).
Qué muestra: las personas naturales (sin empresas) con mayor número de comparendos acumulados.
Cómo leerlo: cada barra horizontal es una persona y el número a la derecha es su cantidad de comparendos. La de arriba es la que más acumula.
Al pasar el cursor: sobre una barra aparecen el nombre, la cantidad de comparendos y el valor acumulado.
Para qué sirve: reconocer a los reincidentes para enfocar campañas educativas y acciones sancionatorias en ellos.
# Top 10 de personas naturales por número de comparendos
pers_all <- datos %>% filter(str_to_upper(genero) != "EMPRESA") %>%
group_by(ejecutado) %>% summarise(n = n(), v = sum(costo_de_comparendo), .groups = "drop")
pers <- pers_all %>% slice_max(n, n = 10, with_ties = TRUE) %>% arrange(n) %>%
mutate(et = wrapbr(ejecutado, 45),
tip = paste0("<b>", ejecutado, "</b><br>", n, " comparendos<br>Valor: ", cop(v)))
p <- plot_ly(pers, x = ~n, y = ~et, type = "bar", orientation = "h", marker = list(color = pal$violeta),
text = ~n, textposition = "outside", cliponaxis = FALSE, textfont = list(size = 14, color = pal$marino),
hoverinfo = "text", hovertext = ~tip, height = 120 + 40 * nrow(pers)) %>%
layout(xaxis = eje_val(max(pers$n) * 1.15, tickformat = "d"), yaxis = eje_cat(pers$et), bargap = 0.3) %>%
pl("Top 10 de personas naturales con más comparendos", leyenda = FALSE)
graf(p)
La persona natural con más comparendos acumula 27, frente a 10 de la siguiente. Hay 289 personas naturales con 2 o más comparendos. Identificar a los reincidentes permite focalizar intervenciones educativas y sancionatorias más precisas.
Consulta 1. Frecuencia de infracciones según el tipo de vehículo
Qué muestra: a la izquierda, qué porcentaje de los comparendos corresponde a autos y a motos; a la derecha, cuántos comparendos hay de cada infracción, separados por tipo de vehículo.
Cómo leerlo: en la dona, cada color es un tipo de vehículo, el porcentaje va dentro del anillo y el total de registros, en el centro. En las barras, la longitud es la cantidad de comparendos y los colores indican cuánto aporta cada vehículo.
Al pasar el cursor: en la dona aparecen el vehículo, la cantidad y el porcentaje; en las barras, la infracción completa y los comparendos de cada vehículo.
Para qué sirve: ver qué vehículo infringe más y en cuáles infracciones pesan más los autos o las motos.
# Dona de participación por vehículo + barras por infracción
q1 <- datos %>% count(vehiculo) %>% mutate(p = n / sum(n))
p_dona <- plot_ly(q1, labels = ~vehiculo, values = ~n, type = "pie", hole = 0.58, sort = FALSE,
direction = "clockwise", textinfo = "percent",
textfont = list(color = "white", size = 17),
marker = list(colors = unname(col_veh[q1$vehiculo]), line = list(color = "white", width = 3)),
hovertemplate = "<b>%{label}</b><br>%{value:,.0f} comparendos<br>%{percent:.1%}<extra></extra>",
height = 460) %>%
layout(annotations = list(list(text = paste0("Total<br><b>", fm(sum(q1$n)), "</b>"), x = 0.5, y = 0.5,
showarrow = FALSE, font = list(size = 18, color = pal$marino)))) %>%
pl("Participación por vehículo", margen = list(t = 70, r = 10, b = 20, l = 10)) %>%
layout(legend = list(orientation = "h", x = 0.5, xanchor = "center", y = -0.02))
q1b <- datos %>% count(infraccion, vehiculo) %>%
mutate(et = wrapbr(infraccion, 24), tip = paste0("<b>", infraccion, "</b><br>", vehiculo, ": ", fm(n), " comparendos"))
orden1 <- q1b %>% group_by(infraccion, et) %>% summarise(t = sum(n), .groups = "drop") %>% arrange(t) %>%
mutate(tip = paste0("<b>", infraccion, "</b><br>Total: ", fm(t), " comparendos"))
p_barras <- plot_ly(height = 460)
for (veh in names(col_veh)) {
p_barras <- add_bars(p_barras, data = filter(q1b, vehiculo == veh), x = ~n, y = ~et, orientation = "h",
name = veh, marker = list(color = col_veh[[veh]]), hoverinfo = "text", hovertext = ~tip)
}
p_barras <- p_barras %>%
add_trace(data = orden1, x = ~t, y = ~et, type = "scatter", mode = "text", text = ~fm(t),
textposition = "middle right", textfont = list(size = 14, color = pal$marino),
showlegend = FALSE, hoverinfo = "text", hovertext = ~tip) %>%
layout(barmode = "stack", xaxis = eje_val(max(orden1$t) * 1.15), yaxis = eje_cat(orden1$et)) %>%
pl("Comparendos por infracción y vehículo")
htmltools::div(class = "dos-col", style = "grid-template-columns:1fr 1.5fr", graf(p_dona), graf(p_barras))
# Tabla de la consulta 1
t1 <- datos %>% group_by(infraccion) %>%
summarise(Auto = sum(vehiculo == "Auto"), Moto = sum(vehiculo == "Moto"), Total = n(), Valor = sum(costo_de_comparendo), .groups = "drop") %>%
arrange(desc(Total)) %>%
mutate(`% registros` = pct(Total / sum(Total)), Valor = cop(Valor), across(c(Auto, Moto, Total), fm)) %>%
rename(`Infracción` = infraccion)
salida(tabla_html(t1))
| Infracción | Auto | Moto | Total | Valor | % registros |
|---|---|---|---|---|---|
| Velocidad superior a la máxima permitida | 1.467 | 159 | 1.626 | $ 418.695.000 | 76,7% |
| No detenerse ante una luz roja o amarilla | 363 | 21 | 384 | $ 197.760.000 | 18,1% |
| No respetar el paso de peatones | 105 | 0 | 105 | $ 27.037.500 | 5,0% |
| Transitar en sentido contrario | 2 | 2 | 4 | $ 206.000 | 0,2% |
En el dashboard esta consulta mostraba solo 396 registros y $ 116.647.500 porque la segmentación de día estaba en DOMINGO. Aquí se usa toda la base: 2.119 registros y $ 643.698.500.
Consulta 2. Distribución de comparendos por propietario y tipo de vehículo
Qué muestra: los 15 propietarios con más comparendos y qué parte de ellos corresponde a autos y a motos.
Cómo leerlo: cada barra horizontal es un propietario; el número al final es su total de comparendos. Los colores dividen la barra entre autos (azul) y motos (coral).
Al pasar el cursor: sobre cada tramo de color aparecen el nombre completo del propietario y los comparendos de ese vehículo.
Para qué sirve: ubicar a los propietarios que más comparendos acumulan, casi siempre entidades financieras o empresas, para priorizar la gestión de cobro.
# Top 15 propietarios, barras apiladas por vehículo
top15 <- prop %>% slice_max(n, n = 15, with_ties = FALSE) %>% arrange(n) %>%
mutate(et = wrapbr(ejecutado, 30), tip = paste0("<b>", ejecutado, "</b><br>Total: ", n, " comparendos"))
q2 <- datos %>% filter(ejecutado %in% top15$ejecutado) %>% count(ejecutado, vehiculo) %>%
mutate(et = wrapbr(ejecutado, 30), tip = paste0("<b>", ejecutado, "</b><br>", vehiculo, ": ", n, " comparendos"))
p <- plot_ly(height = 600)
for (veh in names(col_veh)) {
p <- add_bars(p, data = filter(q2, vehiculo == veh), x = ~n, y = ~et, orientation = "h",
name = veh, marker = list(color = col_veh[[veh]]), hoverinfo = "text", hovertext = ~tip)
}
p <- p %>%
add_trace(data = top15, x = ~n, y = ~et, type = "scatter", mode = "text", text = ~n,
textposition = "middle right", textfont = list(size = 14, color = pal$marino),
showlegend = FALSE, hoverinfo = "text", hovertext = ~tip) %>%
layout(barmode = "stack", xaxis = eje_val(max(top15$n) * 1.12, tickformat = "d"), yaxis = eje_cat(top15$et)) %>%
pl("Los 15 propietarios con más comparendos")
graf(p)
Los propietarios con más comparendos son entidades financieras y empresas (leasing y transporte). Hay 1.247 propietarios distintos y 899 (72%) tienen un solo comparendo. En el dashboard esta consulta estaba limitada a domingos y propietarios con 3 o más comparendos (67 registros).
Consulta 3. Distribución porcentual del valor económico por propietario
Qué muestra: qué porcentaje del dinero total de los comparendos corresponde a los 6 propietarios con mayor valor y qué parte queda en «Otros propietarios».
Cómo leerlo: cada porción de la dona es un propietario y su tamaño es su participación en el valor total; el porcentaje está dentro de la porción y en la leyenda de la derecha. El centro muestra el valor total.
Al pasar el cursor: sobre una porción aparecen el propietario, su valor en pesos y su porcentaje. Si haces clic en la leyenda, ocultas o muestras esa porción.
Para qué sirve: medir qué tan concentrado o repartido está el valor: si «Otros propietarios» es la porción más grande, el valor está muy atomizado.
# Dona del valor económico: top 6 propietarios y el resto
q3 <- datos %>% group_by(ejecutado) %>% summarise(v = sum(costo_de_comparendo), .groups = "drop") %>% arrange(desc(v)) %>%
mutate(grupo = if_else(row_number() <= 6, ejecutado, "Otros propietarios")) %>%
group_by(grupo) %>% summarise(v = sum(v), .groups = "drop") %>%
mutate(p = v / sum(v), orden = if_else(grupo == "Otros propietarios", 0, v)) %>% arrange(desc(orden)) %>%
mutate(et = str_trunc(grupo, 32))
colores3 <- c(pal$azul, pal$turquesa, pal$ambar, pal$coral, pal$violeta, pal$marino, pal$gris)
p <- plot_ly(q3, labels = ~et, values = ~v, type = "pie", hole = 0.58, sort = FALSE,
direction = "clockwise", textinfo = "percent", insidetextorientation = "horizontal",
textfont = list(color = "white", size = 14),
marker = list(colors = colores3[seq_len(nrow(q3))], line = list(color = "white", width = 3)),
hovertemplate = "<b>%{label}</b><br>$ %{value:,.0f}<br>%{percent:.1%}<extra></extra>",
height = 500) %>%
layout(annotations = list(list(text = paste0("Total<br><b>", cop(sum(q3$v)), "</b>"), x = 0.5, y = 0.5,
showarrow = FALSE, font = list(size = 16, color = pal$marino)))) %>%
pl("Valor económico por propietario", margen = list(t = 70, r = 10, b = 20, l = 10)) %>%
layout(legend = list(orientation = "v", x = 1.02, y = 0.5, font = list(size = 13)))
graf(p)
El valor económico está muy atomizado: los 6 mayores propietarios suman solo el 10,5% del valor total. Nota: en el dashboard este gráfico contaba registros, no dinero; aquí se calcula con el valor real del comparendo.
Consulta 4. Top 10 de propietarios con más comparendos
Qué muestra: una tabla con los 10 propietarios que más comparendos acumulan, con su tipo de identificación, cantidad, valor y participación.
Cómo leerlo: cada fila es un propietario, ordenado del que más comparendos tiene al que menos. La columna «% del total» incluye una barrita cuyo largo es proporcional a su participación.
Al pasar el cursor: la fila bajo el cursor se resalta para seguirla con facilidad.
Para qué sirve: tener a la mano la lista concreta de propietarios a priorizar en la gestión de cobro.
# Top 10 de propietarios (conteo de comparendos, no suma de códigos)
q4 <- datos %>% group_by(ejecutado, tipo_id) %>% summarise(n = n(), v = sum(costo_de_comparendo), .groups = "drop") %>%
arrange(desc(n)) %>% slice_head(n = 10) %>% mutate(p = n / nrow(datos))
t4 <- q4 %>% transmute(`#` = row_number(), Propietario = ejecutado, `Tipo de ID` = tipo_id, Comparendos = n,
Valor = cop(v), SMLV = fm(v / smlv_2010),
`% del total` = paste0('<span class="mini" style="width:', as.integer(round(p / max(p) * 60)), 'px"></span>', pct(p)))
salida(tabla_html(t4))
| # | Propietario | Tipo de ID | Comparendos | Valor | SMLV | % del total |
|---|---|---|---|---|---|---|
| 1 | LEASING BANCOLOMBIA S.A. C.F. | NIT | 61 | $ 19.827.500 | 38 | 2,9% |
| 2 | TRANSPORTES MST Y CIA S EN C | NIT | 48 | $ 13.905.000 | 27 | 2,3% |
| 3 | FINANCIERA INTERNACIONAL S.A. | NIT | 32 | $ 10.557.500 | 20 | 1,5% |
| 4 | LEASING DE OCCIDENTE S.A. C.F. | NIT | 28 | $ 9.527.500 | 18 | 1,3% |
| 5 | LILIANA ROZO PINZON | Cédula de ciudadanía | 27 | $ 7.467.500 | 14 | 1,3% |
| 6 | GMAC FINANCIERA DE COLOMBI | NIT | 21 | $ 6.180.000 | 12 | 1,0% |
| 7 | LEASING DE CREDITO S.A. | NIT | 21 | $ 5.922.500 | 12 | 1,0% |
| 8 | UINON FAMILIAR CHARRIS S.EN C | NIT | 13 | $ 4.120.000 | 8 | 0,6% |
| 9 | ELVIRA DEL CARMEN GARRIDO AREVALO | Cédula de ciudadanía | 10 | $ 2.575.000 | 5 | 0,5% |
| 10 | MIGUEL HERNANDO GARAY CALLE | Cédula de ciudadanía | 9 | $ 2.111.500 | 4 | 0,4% |
El top 10 concentra el 12,7% de los comparendos y el 12,8% del valor. Corrección frente al dashboard: la tabla original sumaba el código de la infracción; aquí se cuentan comparendos.
Consulta 5. Frecuencia de infracciones por tipo de identificación y género
Qué muestra: a la izquierda, cuántos comparendos hay según el documento con que se identifica el infractor (cédula de ciudadanía, de extranjería o NIT); a la derecha, cada infracción dividida por género o tipo de titular.
Cómo leerlo: en las columnas, la altura y el número arriba indican la cantidad de comparendos. En las barras horizontales, la longitud es la cantidad de comparendos de cada infracción y los colores indican quién la cometió (mujer, hombre, empresa).
Al pasar el cursor: sobre una columna aparecen el tipo de documento y su cantidad; sobre un tramo de color, la infracción completa y los comparendos de ese género.
Para qué sirve: conocer el perfil de quien comete cada infracción para diseñar mensajes y controles distintos para personas y empresas.
# Barras por tipo de identificación + infracción por género
q5a <- datos %>% count(tipo_id) %>% arrange(desc(n)) %>%
mutate(et = wrapbr(tipo_id, 14), tip = paste0("<b>", tipo_id, "</b><br>", fm(n), " comparendos"))
pa <- plot_ly(q5a, x = ~et, y = ~n, type = "bar",
marker = list(color = c(pal$azul, pal$turquesa, pal$ambar)[seq_len(nrow(q5a))]),
text = ~fm(n), textposition = "outside", cliponaxis = FALSE, textfont = list(size = 14, color = pal$marino),
hoverinfo = "text", hovertext = ~tip, height = 470) %>%
layout(xaxis = eje_cat(q5a$et), yaxis = eje_val(max(q5a$n) * 1.2)) %>%
pl("Por tipo de identificación", leyenda = FALSE, margen = list(t = 70, r = 10, b = 60, l = 20))
q5b <- datos %>% count(infraccion, genero = str_to_title(genero)) %>%
mutate(et = wrapbr(infraccion, 22), tip = paste0("<b>", infraccion, "</b><br>", genero, ": ", fm(n), " comparendos"))
orden5 <- q5b %>% group_by(et) %>% summarise(t = sum(n), .groups = "drop") %>% arrange(t)
pb <- plot_ly(height = 470)
for (g in unique(q5b$genero)) {
pb <- add_bars(pb, data = filter(q5b, genero == g), x = ~n, y = ~et, orientation = "h", name = g,
marker = list(color = unname(col_gen[g])), hoverinfo = "text", hovertext = ~tip)
}
pb <- pb %>% layout(barmode = "stack", xaxis = eje_val(max(orden5$t) * 1.05), yaxis = eje_cat(orden5$et)) %>%
pl("Infracción según género")
htmltools::div(class = "dos-col", style = "grid-template-columns:1fr 1.4fr", graf(pa), graf(pb))
El dashboard mostraba 396 registros y 3 infracciones (solo domingos). La base depurada completa tiene 2.119 registros y 4 infracciones: «Transitar en sentido contrario» solo aparece en días que no son domingo.
Consulta 6. Evolución de los comparendos (semanal y mensual)
Qué muestra: cómo cambian semana a semana el número de comparendos (barras turquesa, eje izquierdo) y el dinero que suman (línea ámbar, eje derecho, en millones de pesos).
Cómo leerlo: cada barra es una semana que empieza el lunes indicado en el eje horizontal; su altura y el número encima son los comparendos. La línea ámbar sube o baja según el valor económico de esa semana. La última semana está incompleta.
Al pasar el cursor: sobre una barra o un punto de la línea aparecen la semana, los comparendos y el valor económico de esa semana.
Para qué sirve: ver si el valor sube igual que la cantidad de comparendos o si cambia por el tipo de infracción, y detectar semanas críticas.
# Barras de comparendos + línea de valor económico (doble eje), por semana
q6 <- datos %>% mutate(semana = lubridate::floor_date(fecha, "week", week_start = 1)) %>%
group_by(semana) %>% summarise(n = n(), v = sum(costo_de_comparendo), .groups = "drop") %>%
mutate(tip = paste0("<b>Semana del ", format(semana, "%d/%m/%Y"), "</b><br>Comparendos: ", fm(n), "<br>Valor: ", cop(v)))
p <- plot_ly(height = 480) %>%
add_bars(data = q6, x = ~semana, y = ~n, width = 5 * 86400000, name = "Comparendos",
marker = list(color = pal$turquesa), text = ~fm(n), textposition = "outside", cliponaxis = FALSE,
textfont = list(size = 14, color = pal$marino), hoverinfo = "text", hovertext = ~tip) %>%
add_trace(data = q6, x = ~semana, y = ~v, yaxis = "y2", type = "scatter", mode = "lines+markers",
name = "Valor económico", line = list(color = pal$ambar, width = 4),
marker = list(color = pal$ambar, size = 9), hoverinfo = "text", hovertext = ~tip) %>%
layout(xaxis = list(title = "", type = "date", tickformat = "%d/%m", tickvals = as.character(q6$semana),
gridcolor = "#E5EAF2", fixedrange = TRUE),
yaxis = eje_val(max(q6$n) * 1.2, title = list(text = "Comparendos", font = list(color = pal$turquesa))),
yaxis2 = list(overlaying = "y", side = "right", range = c(0, max(q6$v) * 1.2), showgrid = FALSE,
zeroline = FALSE, fixedrange = TRUE, tickprefix = "$ ", tickformat = ".2s",
title = list(text = "Valor económico", font = list(color = pal$ambar)))) %>%
pl("Comparendos (barras) y valor (línea) por semana<br><sup>Semana que inicia el lunes indicado; la última está incompleta</sup>",
margen = list(t = 95, r = 90, b = 55, l = 70))
graf(p)
# Resumen mensual
t6 <- datos %>% group_by(Mes = mes) %>%
summarise(Comparendos = n(), Dias = n_distinct(fecha), Valor = sum(costo_de_comparendo), .groups = "drop") %>%
mutate(`Promedio diario` = format(round(Comparendos / Dias, 1), nsmall = 1, decimal.mark = ",", trim = TRUE), Comparendos = fm(Comparendos),
`Días con registros` = Dias, Valor = cop(Valor)) %>% select(-Dias)
salida(tabla_html(t6))
| Mes | Comparendos | Valor | Promedio diario | Días con registros |
|---|---|---|---|---|
| Abril | 711 | $ 216.506.000 | 37,4 | 19 |
| Mayo | 1.408 | $ 427.192.500 | 52,1 | 27 |
Solo se analizan abril (desde el 12/04/2010) y mayo (hasta el 27/05/2010), con 2.119 registros y $ 643.698.500. No permite evaluar tendencias anuales ni estacionalidad; por eso la evolución se presenta por semana.
Hallazgos principales
Los resultados subrayan la importancia de implementar políticas públicas basadas en datos: desde campañas educativas focalizadas hasta operativos estratégicos según el tipo de vehículo, el día y el tipo de infractor. La gestión efectiva de los comparendos no solo debe sancionar, sino también prevenir, orientar y transformar los hábitos de conducción para mejorar la seguridad vial colectiva.
Calidad de los datos
Gestión y control
Política pública
Fuente de datos
Secretaría de Tránsito de Barranquilla. Base de datos de comparendos, abril–mayo de 2010 (archivo BD_Comparendos_TAD_13.xlsx).
Herramientas
Procesamiento y visualización en R version 4.6.1 (2026-06-24 ucrt) con los paquetes tidyverse, plotly, scales y htmltools.