1 Introducción

El presente informe tiene como objetivo aplicar funciones estadísticas básicas al análisis de una base de datos de comparendos de tránsito de la ciudad de Barranquilla, registrados entre abril y mayo de 2010. A través del lenguaje R se exploran, describen y visualizan los datos para identificar patrones y tendencias: cuándo ocurren los comparendos, a quiénes se aplican, qué infracción y qué tipo de vehículo están involucrados y cómo se distribuye el valor a pagar.

# Instalar las librerías que falten (solo la primera vez)
paquetes <- c("readxl", "dplyr", "ggplot2", "scales", "lubridate", "knitr")
faltan <- paquetes[!paquetes %in% rownames(installed.packages())]
if (length(faltan) > 0) install.packages(faltan)

# Cargar librerías necesarias
library(readxl)
library(dplyr)
library(ggplot2)
library(scales)
library(lubridate)
library(knitr)

archivo <- "carlos_andres_suarez_BD_Comparendos.xlsx"
hoja    <- "BD Comparendos OK"

if (!file.exists(archivo)) {
  stop("No se encontró '", archivo, "'. Guárdalo en la misma carpeta que este .Rmd.")
}

df <- read_excel(archivo, sheet = hoja)
names(df) <- trimws(names(df))   # En el Excel, "No. MANDAMIENTO DE PAGO " trae un espacio al final

1.1 Preparación de los datos

La hoja original tiene nombres de columna en mayúsculas, con espacios y puntos (por ejemplo COD. INFRACCION o AÑO), lo que obliga a escribirlos entre comillas invertidas en cada línea de código. Por eso se renombran a un formato simple en minúsculas. Además:

  • Se descartan las siete columnas auxiliares que empiezan por # (#GENERO, #VEHICULO, etc.). Todas valen 1 y solo sirven para contar en las tablas dinámicas de Excel.
  • La fecha del comparendo y la fecha del mandamiento de pago pasan a ser fechas reales (esta última viene como texto dd/mm/aaaa).
  • La identificación se guarda como texto (es un identificador, no una cantidad).
  • El género, el tipo de vehículo y el mes se convierten en factores con etiquetas legibles y en orden lógico.
  • El valor se redondea a pesos enteros, porque en Excel aparece como 257500.00000000003.
  • Se crea la columna dia_semana.
dias_semana <- c("Lunes", "Martes", "Miércoles", "Jueves", "Viernes", "Sábado", "Domingo")

datos <- df %>%
  select(-starts_with("#")) %>%
  transmute(
    numero_mandamiento_pago = `No. MANDAMIENTO DE PAGO`,
    fecha_mandamiento_pago  = dmy(as.character(`FECHA MANDAMIENTO DE PAGO`)),
    ejecutado               = EJECUTADO,
    tipo_identificacion     = `TIPO DE IDENTIFICACION`,
    numero_identificacion   = format(`No. IDENTIFICACION`, scientific = FALSE, trim = TRUE),
    genero                  = factor(GENERO,
                                     levels = c("MUJER", "HOMBRE", "EMPRESA"),
                                     labels = c("Mujer", "Hombre", "Empresa")),
    codigo_infraccion       = `COD. INFRACCION`,
    nombre_infraccion       = paste0(toupper(substring(NOM.INFRACCION, 1, 1)),
                                     substring(NOM.INFRACCION, 2)),
    comparendo              = COMPARENDO,
    fecha_comparendo        = as.Date(`FECHA DE COMPARENDO`),
    anio                    = `AÑO`,
    mes                     = MES,
    nombre_mes              = factor(`NOM MES`,
                                     levels = c("ABRIL", "MAYO"),
                                     labels = c("Abril", "Mayo")),
    dia                     = DIA,
    placa_vehiculo          = `PLACA DE VEHICULO`,
    vehiculo                = factor(VEHICULO,
                                     levels = c("AUTO", "MOTO"),
                                     labels = c("Auto", "Moto")),
    valor_a_pagar           = round(Valor)
  ) %>%
  mutate(
    dia_semana = factor(dias_semana[wday(fecha_comparendo, week_start = 1)],
                        levels = dias_semana)
  )

# Funciones auxiliares para mostrar números con formato colombiano (1.234,5)
fmt  <- function(x) format(x, big.mark = ".", decimal.mark = ",", scientific = FALSE, trim = TRUE)
fmt1 <- function(x) format(round(x, 1), big.mark = ".", decimal.mark = ",", nsmall = 1, trim = TRUE)

1.2 Descripción general

La base de datos contiene registros de comparendos de tránsito aplicados en Barranquilla (Atlántico) entre el 12/04/2010 y el 27/05/2010. Cada fila es un comparendo e incluye información del infractor (nombre o razón social, tipo y número de identificación y categoría: hombre, mujer o empresa), el código y el nombre de la infracción, la fecha del comparendo (completa y desglosada en año, mes, nombre del mes y día), la placa y el tipo de vehículo (auto o moto) y el valor a pagar. Todos los mandamientos de pago tienen la misma fecha (19/08/2010).

La hoja original tiene 25 columnas y 2.120 registros. Después de descartar las columnas auxiliares y agregar dia_semana, la base de trabajo queda con 18 columnas y 2.120 registros, con 0 valores faltantes.

1.2.1 Variables de la base

variables <- data.frame(
  Variable = c("numero_mandamiento_pago", "fecha_mandamiento_pago", "ejecutado",
               "tipo_identificacion", "numero_identificacion", "genero",
               "codigo_infraccion", "nombre_infraccion", "comparendo", "fecha_comparendo",
               "anio", "mes", "nombre_mes", "dia",
               "placa_vehiculo", "vehiculo", "valor_a_pagar", "dia_semana"),
  `Columna en el Excel` = c("No. MANDAMIENTO DE PAGO", "FECHA MANDAMIENTO DE PAGO", "EJECUTADO",
                            "TIPO DE IDENTIFICACION", "No. IDENTIFICACION", "GENERO",
                            "COD. INFRACCION", "NOM.INFRACCION", "COMPARENDO", "FECHA DE COMPARENDO",
                            "AÑO", "MES", "NOM MES", "DIA",
                            "PLACA DE VEHICULO", "VEHICULO", "Valor", "(calculada en R)"),
  Descripción = c("Número del mandamiento de pago",
                  "Fecha del mandamiento de pago",
                  "Nombre de la persona o razón social de la empresa",
                  "Tipo de documento (cédula de ciudadanía, NIT, cédula de extranjería)",
                  "Número de identificación",
                  "Categoría del infractor (mujer, hombre, empresa)",
                  "Código numérico de la infracción",
                  "Descripción de la infracción",
                  "Número del comparendo",
                  "Fecha en que se impuso el comparendo",
                  "Año del comparendo", "Número del mes", "Nombre del mes", "Día del mes",
                  "Placa del vehículo",
                  "Tipo de vehículo (auto o moto)",
                  "Valor a pagar en pesos colombianos",
                  "Día de la semana del comparendo"),
  check.names = FALSE
)
kable(variables)
Variable Columna en el Excel Descripción
numero_mandamiento_pago No. MANDAMIENTO DE PAGO Número del mandamiento de pago
fecha_mandamiento_pago FECHA MANDAMIENTO DE PAGO Fecha del mandamiento de pago
ejecutado EJECUTADO Nombre de la persona o razón social de la empresa
tipo_identificacion TIPO DE IDENTIFICACION Tipo de documento (cédula de ciudadanía, NIT, cédula de extranjería)
numero_identificacion No. IDENTIFICACION Número de identificación
genero GENERO Categoría del infractor (mujer, hombre, empresa)
codigo_infraccion COD. INFRACCION Código numérico de la infracción
nombre_infraccion NOM.INFRACCION Descripción de la infracción
comparendo COMPARENDO Número del comparendo
fecha_comparendo FECHA DE COMPARENDO Fecha en que se impuso el comparendo
anio AÑO Año del comparendo
mes MES Número del mes
nombre_mes NOM MES Nombre del mes
dia DIA Día del mes
placa_vehiculo PLACA DE VEHICULO Placa del vehículo
vehiculo VEHICULO Tipo de vehículo (auto o moto)
valor_a_pagar Valor Valor a pagar en pesos colombianos
dia_semana (calculada en R) Día de la semana del comparendo

2 Aplicación de funciones

2.1 Función colnames()

La función colnames() devuelve un vector con los nombres de las columnas. Sirve para identificarlas y llamarlas correctamente en el resto del análisis. Primero se muestran los nombres de la hoja original y luego los de la base de trabajo.

colnames(df)      # Nombres originales de la hoja de Excel
##  [1] "No. MANDAMIENTO DE PAGO"   "FECHA MANDAMIENTO DE PAGO"
##  [3] "EJECUTADO"                 "TIPO DE IDENTIFICACION"   
##  [5] "#TIPO DE IDENTIFICACION"   "No. IDENTIFICACION"       
##  [7] "GENERO"                    "#GENERO"                  
##  [9] "COD. INFRACCION"           "#COD. INFRACCION"         
## [11] "NOM.INFRACCION"            "#NOM.INFRACCION"          
## [13] "COMPARENDO"                "FECHA DE COMPARENDO"      
## [15] "AÑO"                       "MES"                      
## [17] "NOM MES"                   "#NOM MES"                 
## [19] "DIA"                       "NOM DIA"                  
## [21] "#NOM DIA"                  "PLACA DE VEHICULO"        
## [23] "VEHICULO"                  "#VEHICULO"                
## [25] "Valor"
colnames(datos)   # Nombres de la base de trabajo
##  [1] "numero_mandamiento_pago" "fecha_mandamiento_pago" 
##  [3] "ejecutado"               "tipo_identificacion"    
##  [5] "numero_identificacion"   "genero"                 
##  [7] "codigo_infraccion"       "nombre_infraccion"      
##  [9] "comparendo"              "fecha_comparendo"       
## [11] "anio"                    "mes"                    
## [13] "nombre_mes"              "dia"                    
## [15] "placa_vehiculo"          "vehiculo"               
## [17] "valor_a_pagar"           "dia_semana"
dim(datos)        # Filas y columnas
## [1] 2120   18
head(datos, 5)    # Primeras filas

2.2 Función resumen

La función summary() entrega un resumen estadístico (mínimo, cuartiles, mediana, media y máximo) de la fecha del comparendo y del valor a pagar.

summary(datos[, c("fecha_comparendo", "valor_a_pagar")])
##  fecha_comparendo     valor_a_pagar   
##  Min.   :2010-04-12   Min.   :257500  
##  1st Qu.:2010-04-27   1st Qu.:257500  
##  Median :2010-05-06   Median :257500  
##  Mean   :2010-05-05   Mean   :304749  
##  3rd Qu.:2010-05-16   3rd Qu.:257500  
##  Max.   :2010-05-27   Max.   :515000

La fecha de los comparendos va del 12/04/2010 al 27/05/2010. El valor a pagar no es constante: toma 2 valores distintos (257.500 y 515.000 pesos), con un promedio de 304.748,8 pesos por comparendo. Más adelante se ve que el valor depende del tipo de infracción.

3 Aplicación de medidas y análisis

3.1 Comparendos por día

Se cuenta cuántos comparendos hubo en cada fecha para ver la evolución diaria.

por_dia <- datos %>%
  count(fecha_comparendo, name = "comparendos")   # Comparendos por fecha

ggplot(por_dia, aes(x = fecha_comparendo, y = comparendos)) +
  geom_line(color = "steelblue", linewidth = 0.8) +
  geom_point(color = "steelblue") +
  scale_x_date(date_breaks = "1 week", date_labels = "%d/%m") +
  labs(title = "Comparendos por día",
       x = "Fecha del comparendo (día/mes)",
       y = "Cantidad de comparendos")

Se registraron comparendos en 46 días distintos, con un promedio de 46,1 comparendos por día. El día con más comparendos fue el 01/05/2010 (89) y el de menos fue el 27/05/2010 (18). 5 de los 5 días con más comparendos fueron sábado o domingo.

Para confirmar si hay un patrón semanal se calcula el promedio de comparendos por día de la semana (se usa el promedio y no el total porque algunos días de la semana aparecen más veces que otros en el período).

por_semana <- datos %>%
  count(fecha_comparendo, dia_semana, name = "comparendos") %>%
  group_by(dia_semana) %>%
  summarise(total = sum(comparendos),
            dias = n(),
            promedio = round(total / dias, 1),
            .groups = "drop")

kable(por_semana,
      col.names = c("Día de la semana", "Total de comparendos",
                    "Días en el período", "Promedio por día"))
Día de la semana Total de comparendos Días en el período Promedio por día
Lunes 295 7 42.1
Martes 264 7 37.7
Miércoles 273 7 39.0
Jueves 256 7 36.6
Viernes 264 6 44.0
Sábado 372 6 62.0
Domingo 396 6 66.0
ggplot(por_semana, aes(x = dia_semana, y = promedio,
                       fill = dia_semana %in% c("Sábado", "Domingo"))) +
  geom_col(show.legend = FALSE) +
  geom_text(aes(label = promedio), vjust = -0.4) +
  scale_fill_manual(values = c("FALSE" = "steelblue", "TRUE" = "darkorange")) +
  scale_y_continuous(expand = expansion(mult = c(0, 0.1))) +
  labs(title = "Promedio de comparendos por día de la semana",
       x = "Día de la semana",
       y = "Promedio de comparendos por día")

Los fines de semana (sábado y domingo) promedian 64,0 comparendos por día, frente a 39,8 de lunes a viernes: 1,6 veces más. Esto puede ayudar a programar los operativos de control en los días de mayor registro.

3.2 Comparendos por género

Se cuenta la cantidad de comparendos según la categoría del infractor registrada en la columna genero (mujer, hombre o empresa). La categoría Empresa corresponde a los infractores identificados con NIT.

por_genero <- datos %>%
  group_by(genero) %>%
  summarise(comparendos = n(),
            total = sum(valor_a_pagar),
            .groups = "drop") %>%
  mutate(genero = as.character(genero),
         porcentaje = round(100 * comparendos / sum(comparendos), 1)) %>%
  arrange(desc(comparendos))

por_genero %>%
  transmute(`Categoría` = genero,
            `Comparendos` = comparendos,
            `Porcentaje (%)` = porcentaje,
            `Valor total (pesos)` = fmt(total)) %>%
  kable()
Categoría Comparendos Porcentaje (%) Valor total (pesos)
Mujer 970 45.8 296.640.000
Hombre 683 32.2 206.772.500
Empresa 467 22.0 142.655.000
ggplot(por_genero, aes(x = reorder(genero, -comparendos), y = comparendos, fill = genero)) +
  geom_col(show.legend = FALSE) +
  geom_text(aes(label = comparendos), vjust = -0.4) +
  scale_y_continuous(expand = expansion(mult = c(0, 0.1))) +
  labs(title = "Distribución de comparendos por género/empresa",
       x = "Categoría del infractor",
       y = "Cantidad de comparendos")

La categoría con más comparendos es Mujer con 970 (45,8 % del total), seguida de Hombre con 683 (32,2 %). Las empresas concentran 22,0 % de los comparendos, un volumen considerable que justifica controles sobre flotas y vehículos de personas jurídicas.

3.3 Valor total a pagar por tipo de infracción

Se agrupan los comparendos por código de infracción y se suma el valor a pagar de cada grupo. En la base cada código tiene asociado un nombre y un valor propio.

recaudo <- datos %>%
  group_by(codigo_infraccion, nombre_infraccion) %>%
  summarise(comparendos = n(),
            valor_unitario = max(valor_a_pagar),
            valores_distintos = n_distinct(valor_a_pagar),
            total = sum(valor_a_pagar, na.rm = TRUE),
            .groups = "drop") %>%
  mutate(pct_comparendos = round(100 * comparendos / sum(comparendos), 1),
         pct_valor = round(100 * total / sum(total), 1)) %>%
  arrange(desc(total))

recaudo %>%
  transmute(`Código` = codigo_infraccion,
            `Infracción` = nombre_infraccion,
            `Comparendos` = comparendos,
            `% de comparendos` = pct_comparendos,
            `Valor por comparendo (pesos)` = fmt(valor_unitario),
            `Total a pagar (pesos)` = fmt(total),
            `% del valor total` = pct_valor) %>%
  kable()
Código Infracción Comparendos % de comparendos Valor por comparendo (pesos) Total a pagar (pesos) % del valor total
64 Velocidad superior a la maxima permitida 1626 76.7 257.500 418.695.000 64.8
77 No detenerse ante una luz roja o amarilla 385 18.2 515.000 198.275.000 30.7
67 No respetar el paso de peatones 105 5.0 257.500 27.037.500 4.2
76 Transitar en sentido contrario 4 0.2 515.000 2.060.000 0.3
ggplot(recaudo, aes(x = reorder(nombre_infraccion, total), y = total)) +
  geom_col(fill = "darkred") +
  geom_text(aes(label = paste0(format(round(total / 1e6, 1), decimal.mark = ",", trim = TRUE), " M")),
            hjust = -0.1) +
  coord_flip() +
  scale_x_discrete(labels = label_wrap(30)) +
  scale_y_continuous(labels = label_number(scale = 1e-6, suffix = " M",
                                           big.mark = ".", decimal.mark = ","),
                     expand = expansion(mult = c(0, 0.15))) +
  labs(title = "Valor total a pagar por tipo de infracción",
       x = "Infracción",
       y = "Valor total a pagar (millones de pesos)")

El valor total a pagar de los 2.120 comparendos es de 646.067.500 pesos. La infracción con mayor valor es velocidad superior a la maxima permitida (código 64), con 1.626 comparendos y 64,8 % del total; le sigue no detenerse ante una luz roja o amarilla (código 77), con 385 comparendos. Entre las dos reúnen 95,5 % del valor total, mientras que la menos frecuente solo tiene 4 comparendos.

Cada código de infracción tiene un único valor por comparendo, por lo que el total de cada infracción depende de cuántos comparendos tiene y de ese valor. La segunda infracción reúne solo 18,2 % de los comparendos, pero aporta 30,7 % del valor, porque cada uno cuesta 515.000 pesos frente a 257.500 de la primera. Por eso el ranking por valor no coincide con el ranking por cantidad.

3.4 Comparendos por tipo de vehículo

Se agrupa la información por tipo de vehículo y se cuenta la cantidad de comparendos de cada uno, junto con el valor total a pagar.

por_vehiculo <- datos %>%
  group_by(vehiculo) %>%
  summarise(comparendos = n(),
            total = sum(valor_a_pagar),
            .groups = "drop") %>%
  mutate(vehiculo = as.character(vehiculo),
         porcentaje = round(100 * comparendos / sum(comparendos), 1)) %>%
  arrange(desc(comparendos))

por_vehiculo %>%
  transmute(`Tipo de vehículo` = vehiculo,
            `Comparendos` = comparendos,
            `Porcentaje (%)` = porcentaje,
            `Valor total (pesos)` = fmt(total)) %>%
  kable()
Tipo de vehículo Comparendos Porcentaje (%) Valor total (pesos)
Auto 1938 91.4 593.280.000
Moto 182 8.6 52.787.500
ggplot(por_vehiculo, aes(x = reorder(vehiculo, -comparendos), y = comparendos)) +
  geom_col(fill = "darkgreen") +
  geom_text(aes(label = comparendos), vjust = -0.4) +
  scale_y_continuous(expand = expansion(mult = c(0, 0.1))) +
  labs(title = "Comparendos por tipo de vehículo",
       x = "Tipo de vehículo",
       y = "Cantidad de comparendos")

Los autos concentran la mayor cantidad de comparendos: 1.938 (91,4 %), frente a 182 de motos (8,6 %).

3.5 Comparendos por mes

Se agrupan los comparendos por el mes en que ocurrieron para revisar la variación mensual.

por_mes <- datos %>%
  group_by(nombre_mes) %>%
  summarise(comparendos = n(),
            dias_con_registros = n_distinct(fecha_comparendo),
            promedio_diario = round(comparendos / dias_con_registros, 1),
            .groups = "drop")

kable(por_mes, col.names = c("Mes", "Comparendos", "Días con registros", "Promedio por día"))
Mes Comparendos Días con registros Promedio por día
Abril 712 19 37.5
Mayo 1408 27 52.1
ggplot(por_mes, aes(x = nombre_mes, y = comparendos)) +
  geom_col(fill = "purple") +
  geom_text(aes(label = comparendos), vjust = -0.4) +
  scale_y_continuous(expand = expansion(mult = c(0, 0.1))) +
  labs(title = "Comparendos por mes",
       x = "Mes",
       y = "Cantidad de comparendos")

En mayo se registraron 1.408 comparendos y en abril 712, un aumento de 97,8 % en el total. Sin embargo, la comparación directa engaña: abril solo tiene 19 días de registro (desde el 12) y mayo tiene 27 (hasta el 27). Por día, el promedio pasa de 37,5 en abril a 52,1 en mayo, un aumento de 38,9 %, que es la cifra más justa para comparar.

3.6 Top 10 personas con más comparendos

Se identifican las 10 personas con más comparendos registrados, excluyendo las empresas. El conteo se hace por el nombre del ejecutado; en la base hay algunos nombres con más de un número de identificación (y al revés), así que cifras pequeñas podrían variar ligeramente si se contara por identificación.

conteo_personas <- datos %>%
  filter(genero != "Empresa") %>%          # Excluir empresas
  count(ejecutado, name = "comparendos", sort = TRUE)

top_personas <- conteo_personas %>%
  slice_head(n = 10)                       # Las 10 primeras

ggplot(top_personas, aes(x = reorder(ejecutado, comparendos), y = comparendos)) +
  geom_col(fill = "brown") +
  geom_text(aes(label = comparendos), hjust = -0.2) +
  coord_flip() +
  scale_x_discrete(labels = label_wrap(30)) +
  scale_y_continuous(expand = expansion(mult = c(0, 0.1))) +
  labs(title = "Top 10 personas con más comparendos",
       x = "Nombre",
       y = "Cantidad de comparendos")

La persona con más comparendos registra 27, es decir, 2,7 veces los de la segunda (10). El resto del listado va de 9 a 6 comparendos. Hay 3 personas más con 6 comparendos que quedan por fuera del listado por empate. Casos con tantos comparendos en pocas semanas son reincidencias que permiten enfocar acciones educativas y de control sobre esos infractores.

4 Conclusión

El análisis de los 2.120 comparendos registrados entre el 12/04/2010 y el 27/05/2010 muestra patrones claros. Hubo en promedio 46,1 comparendos por día, y los fines de semana el registro es mucho mayor (64,0 por día frente a 39,8 de lunes a viernes). Por mes, el promedio diario también subió de abril a mayo.

Por tipo de infractor, Mujer es la categoría con más comparendos (45,8 %) y las empresas aportan 22,0 %. Por tipo de vehículo, los autos representan 91,4 % de los comparendos. En cuanto a las infracciones, la de código 64 concentra 64,8 % del valor total a pagar y las dos primeras suman 95,5 %; la infracción de código 77, aunque tiene menos comparendos, pesa más en el valor porque cada comparendo cuesta 515.000 pesos. La reincidencia también es visible: una sola persona acumula 27 comparendos.

Estos resultados sugieren que los operativos de control podrían concentrarse en los fines de semana, que las campañas deben dirigirse a las conductas más frecuentes y a las de mayor valor, y que conviene hacer seguimiento a los reincidentes y a las flotas de empresas. El uso de R permitió automatizar el procesamiento de los datos y generar un informe reproducible que facilita futuros análisis.

5 Referencias

  • Base de datos de comparendos de tránsito de Barranquilla, abril–mayo de 2010.
  • R Core Team. R: A Language and Environment for Statistical Computing. R Foundation for Statistical Computing, Viena, Austria. https://www.R-project.org/
  • Wickham, H. (2016). ggplot2: Elegant Graphics for Data Analysis. Springer-Verlag, Nueva York.
  • Wickham, H., François, R., Henry, L. y Müller, K. dplyr: A Grammar of Data Manipulation. Paquete de R. https://dplyr.tidyverse.org
  • Wickham, H. y Bryan, J. readxl: Read Excel Files. Paquete de R. https://readxl.tidyverse.org
  • Spinu, V., Grolemund, G. y Wickham, H. lubridate: Make Dealing with Dates a Little Easier. Paquete de R. https://lubridate.tidyverse.org
  • Xie, Y., Allaire, J. J. y Grolemund, G. (2018). R Markdown: The Definitive Guide. Chapman and Hall/CRC.