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
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:
# (#GENERO, #VEHICULO, etc.).
Todas valen 1 y solo sirven para contar en las tablas dinámicas de
Excel.dd/mm/aaaa).257500.00000000003.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)
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.
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 |
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
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.
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.
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.
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.
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 %).
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.
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.
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.