CARGUE DE LOS ARCHIVOS

Se trata de dos archivos excel: validación de evidencias por agente y reporte de evidencia

library(openxlsx)
val_agente = read.xlsx("/home/dferroa/Documentos/Secretaria de Movilidad/CAMARAS/VALIDACION DE EVIDENCIAS POR AGENTE_oct-dic-2024.xlsx")

registro = read.xlsx("/home/dferroa/Documentos/Secretaria de Movilidad/CAMARAS/Reporte_evidencias_de_oct_a_dic_2024.xlsx")

UNION DE ARCHIVOS

registros_agentes = left_join(registro, val_agente, by = c('FECHA.EVIDENCIA','CAMARA','PLACA','INFRACCIONES.APROBADAS','INFRACCIONES.RECHAZADAS')) %>% 
  mutate(COMPARENDO.APROBADO = ifelse(ESTADO == "aprobado", 1,0)) %>% 
  mutate(COMPARENDO.RECHAZADO = ifelse(ESTADO == "rechazado", 1,0)) 
## Warning in left_join(registro, val_agente, by = c("FECHA.EVIDENCIA", "CAMARA", : Detected an unexpected many-to-many relationship between `x` and `y`.
## ℹ Row 2628 of `x` matches multiple rows in `y`.
## ℹ Row 282141 of `y` matches multiple rows in `x`.
## ℹ If a many-to-many relationship is expected, set `relationship =
##   "many-to-many"` to silence this warning.
colnames(registros_agentes)
##  [1] "FECHA.EVIDENCIA"          "HORA.EVIDENCIA.x"        
##  [3] "PUNTO.DE.FOTODETECCION"   "CAMARA"                  
##  [5] "PLACA"                    "VELOCIDAD.DEL.VEHICULO"  
##  [7] "VELOCIDAD.LIMITE"         "ESTADO"                  
##  [9] "TIPO"                     "INFRACCIONES.POR.VALIDAR"
## [11] "INFRACCIONES.APROBADAS"   "INFRACCIONES.RECHAZADAS" 
## [13] "CLASE.VEHICULO"           "TIPO.SERVICIO"           
## [15] "MODALIDAD.DE.SERVICIO"    "LOCALIDAD"               
## [17] "HORA.EVIDENCIA.y"         "FECHA.VALIDACION"        
## [19] "HORA.VALIDACION"          "IDENTIFICACION.AGENTE"   
## [21] "MOTIVO"                   "OBSERVACIONES"           
## [23] "COMPARENDO.APROBADO"      "COMPARENDO.RECHAZADO"

Evidecia de duplicado

duplicados <- duplicated(registros_agentes)
sum(duplicados)
## [1] 0
sum(duplicados_columnas <- registros_agentes %>%
  duplicated(subset = c("PLACA", "FECHA.EVIDENCIA")))
## [1] 0

GRÁFICA GENERAL DE NÚMERO DE REVISIÓN DE EVIDENCIAS POR AGENTE

evidenciaXagente = registros_agentes %>%
  group_by(IDENTIFICACION.AGENTE) %>%
  summarise(CONTEO = n(), 
          PORCENTAJE = round((n() / nrow(registros_agentes))* 100,1) ,
          .groups = "drop") %>% 
  as.data.frame()

ggplot(evidenciaXagente, aes(x = reorder(IDENTIFICACION.AGENTE, -CONTEO), y = CONTEO)) +
  geom_bar(stat = "identity", fill = "#b1615c") + # Usar un color específico de Cassatt1
  geom_text(aes(label = paste0(PORCENTAJE, "%")), vjust = -0.5, size = 2.2) + # Agregar etiquetas de porcentaje
  labs(
    title = "Evidencias revisadas por Agente",
    x = "Agentes",
    y = "Conteo"
  ) +
  theme_minimal() +
  theme(
    axis.text.x = element_text(angle = 45, hjust = 0.8), # Rotar los nombres de los agentes
    plot.title = element_text(hjust = 0.5, size = 16, face = "bold") # Ajustar el título
  )

## GRÁFICA GENERAL DE PARETO DEL NÚMERO DE REVISIÓN DE EVIDENCIAS POR AGENTE

evidenciaXagente <- evidenciaXagente %>%
  arrange(desc(CONTEO)) %>%
  mutate(PORCENTAJE_ACUMULADO = cumsum(PORCENTAJE))

punto_80 <- evidenciaXagente %>%
  filter(PORCENTAJE_ACUMULADO >= 80) %>%
  slice(1) 

ggplot(evidenciaXagente, aes(x = reorder(IDENTIFICACION.AGENTE, -CONTEO), y = CONTEO)) +
  geom_bar(stat = "identity", fill = "#b1615c") +  # Barras de conteo
  geom_line(aes(y = PORCENTAJE_ACUMULADO * max(CONTEO) / 100), # Línea acumulada
            group = 1, color = "blue", linewidth = 0.5) +
  geom_point(aes(y = PORCENTAJE_ACUMULADO * max(CONTEO) / 100), color = "blue") +
  # Resaltar el punto del 80% en la línea acumulada en la misma altura
  geom_point(data = punto_80, aes(x = IDENTIFICACION.AGENTE, 
                                  y = PORCENTAJE_ACUMULADO * max(CONTEO) / 100), 
             color = "red", size = 4) +  # Resaltamos el punto en la línea acumulada
  geom_text(aes(label = paste0(PORCENTAJE, "%")), vjust = -0.5, size = 2) + # Etiquetas de porcentaje
  labs(
    title = "Análisis de Pareto: Conteo y Porcentaje Acumulado por Agente",
    x = "Agentes",
    y = "Conteo",
    caption = "Línea azul: Porcentaje acumulado"
  ) +
  scale_y_continuous(
    sec.axis = sec_axis(~ . * 100 / max(evidenciaXagente$CONTEO), name = "Porcentaje Acumulado (%)") # Eje secundario para porcentaje
  ) +
  theme_minimal() +
  theme(
    axis.text.x = element_text(angle = 45, hjust = 1, size = 4), # Rotar los nombres de los agentes
    plot.title = element_text(hjust = 0.5, size = 16, face = "bold") # Ajustar el título
  )

Los agentes que concentran el 80% de la revisión de evidencias de oct a dic de 2024 son:

ochenta_agentes = evidenciaXagente %>%
  mutate(PORCENTAJE_ACUMULADO = cumsum(PORCENTAJE)) %>%
  filter(PORCENTAJE_ACUMULADO <= 80) 

print(ochenta_agentes$IDENTIFICACION.AGENTE)
##  [1] "AGENTE 6"  NA          "AGENTE 8"  "AGENTE 3"  "AGENTE 16" "AGENTE 12"
##  [7] "AGENTE 2"  "AGENTE 18" "AGENTE 24" "AGENTE 19" "AGENTE 17" "AGENTE 22"
## [13] "AGENTE 26" "AGENTE 13"

AGENTES QUE MÁS IMPUSIERON COMPARENDOS POR VELOCIDAD

comparendo_aprobado = 
  registros_agentes %>% 
  filter(COMPARENDO.APROBADO == 1) %>% 
  group_by(IDENTIFICACION.AGENTE)%>% 
  summarise(CONTEO = n()) %>% 
  ungroup() %>% 
  mutate(APROBADO = round((CONTEO/sum(registros_agentes$COMPARENDO.APROBADO)* 100),1)) %>%
  as.data.frame() 

ggplot(comparendo_aprobado, aes(x = reorder(IDENTIFICACION.AGENTE, -APROBADO), y = APROBADO)) +
  geom_bar(stat = "identity", , fill = "#b1615c", show.legend = FALSE) +
  geom_text(aes(label = paste0(APROBADO, "%")), hjust = -0.3, size = 2, vjust = 0.5) +
  labs(title = "Porcentaje comparendos aprobados por agente",
       x = "Agente",
       y = "Porcentaje") +
  coord_flip()+
  theme_minimal()+
  theme(axis.text.y = element_text(size = 6, angle = 0, vjust = 0.5, hjust = 0.5),
        plot.title = element_text(hjust = 0.5, size = 16, face = "bold")) 

## AGENTES QUE MENOS IMPUSIERON COMPARENDOS POR VELOCIDAD

comparendo_rechazado = 
  registros_agentes %>% 
  filter(COMPARENDO.RECHAZADO == 1) %>% 
  group_by(IDENTIFICACION.AGENTE)%>% 
  summarise(CONTEO = n()) %>% 
  ungroup() %>% 
  mutate(RECHAZADO = round((CONTEO/sum(registros_agentes$COMPARENDO.RECHAZADO)* 100),1)) %>%
  as.data.frame() %>%
  arrange(desc(RECHAZADO))

ggplot(comparendo_rechazado, aes(x = reorder(IDENTIFICACION.AGENTE, -RECHAZADO), y = RECHAZADO)) +
  geom_bar(stat = "identity", , fill = "#b1615c", show.legend = FALSE) +
  geom_text(aes(label = paste0(RECHAZADO, "%")), hjust = -0.3, size = 2, vjust = 0.5) +
  labs(title = "Porcentaje comparendos rechazados por agente",
       x = "Agente",
       y = "Porcentaje") +
  coord_flip()+
  theme_minimal()+
  theme(axis.text.y = element_text(size = 6, angle = 0, vjust = 0.5, hjust = 0.5),
        plot.title = element_text(hjust = 0.5, size = 16, face = "bold")) 

## PORCENTAJE RECHAZOS Y APROBADOS POR AGENTE

aprobado_rechazadoXagente <- registros_agentes %>%
  group_by(IDENTIFICACION.AGENTE, ESTADO) %>%
  summarise(CONTEO = n()) %>%
  mutate(PORCENTAJE = round(100 * CONTEO / sum(CONTEO), 2)) %>%
  as.data.frame() 
## `summarise()` has grouped output by 'IDENTIFICACION.AGENTE'. You can override
## using the `.groups` argument.
color_apr <- met.brewer(name = "Cassatt1", n = 8, type = "discrete")[1]
color_rec <- met.brewer(name = "Cassatt1", n = 8, type = "discrete")[8]

ggplot(aprobado_rechazadoXagente, aes(x = IDENTIFICACION.AGENTE, y = PORCENTAJE, fill = ESTADO)) +
  geom_bar(stat = "identity", position = position_dodge(width = 0.9)) +
  geom_text(aes(label = paste0(PORCENTAJE, "%")), 
            position = position_dodge(width = 0.9), 
            size = 1.2, # Tamaño ajustado para mejor visibilidad
            hjust = -0.1) + # Ajusta la posición horizontal de las etiquetas
  ylim(0, 100) +
  labs(title = "Porcentaje de evidencias por estado y por agente", 
       x = "Agente", 
       y = "Porcentaje (%)",
       caption = "Fuente: ") +
  scale_fill_manual(values = c("aprobado" = color_apr, "rechazado" = color_rec)) +
  theme_minimal() +
  theme(plot.caption = element_text(size = 8, hjust = 0.5, face = "italic", color = "grey"), 
        legend.text = element_text(size = 8), 
        legend.title = element_text(size = 9), 
        legend.key.size = unit(0.4, "cm"), 
        legend.spacing.y = unit(0.2, "cm"), 
        legend.margin = margin(0, 0, 0, 0),
        axis.text.y = element_text(size = 5, angle = 0, vjust = 0.5, hjust = 0.5)) +
  coord_flip()

## RAZONES DE RECHAZO EN GENERAL

motivos <- c("BAJA CALIDAD O FALLA EN FOTOGRAFIA", 
             "NO APLICA INFRACCIÓN AL TIPO DE VEHICULO",
             "SUPERO INFRACCIONES IMPUESTAS POR DIA AL MISMO CONDUCTOR",
             "BAJA CALIDAD O FALLA EN VIDEO",
             "ERROR EN CARGUE DE FOTO O VIDEO",
             "NO SE EVIDENCIA INFRACCION O FALLA EN CAMARA",
             "ERROR EN IDENTIFICACIÓN DE PLACA",
             "EXCEDER TIEMPO LIMITE LEGAL PARA VALIDAR",
             "FACTORES AMBIENTALES",
             "FACTORES HUMANOS",
             "FORMATO NO DILIGENCIADO CORRECTAMENTE",
             "INCONSISTENCIA CARACTERISTICAS DEL VEHICULO",
             "INFORMACION INSUFICIENTE PARA GENERAR UN COMPARENDO",
             "NO REGISTRA DATOS SUFICIENTES",
             "VEHICULO FUERA DE RANGO DE VIDEO")


for (MOTIVO_ACTUAL in motivos) {
  registros_agentes[[MOTIVO_ACTUAL]] <- as.integer(grepl(MOTIVO_ACTUAL, registros_agentes$MOTIVO))
}

motivos_por_agente <- registros_agentes %>%
  group_by(IDENTIFICACION.AGENTE) %>%
  summarise(CONTEO_GENERAL= n(),across(all_of(motivos), sum, .names = "count_{.col}")) %>%
  mutate(across(starts_with("count_"), ~ round((./ CONTEO_GENERAL)*100,1), .names = "prop_{.col}")) %>%
  mutate(orden = match(IDENTIFICACION.AGENTE, comparendo_rechazado$IDENTIFICACION.AGENTE)) %>%
  arrange(orden) %>%
  select(-orden) %>%
  select(IDENTIFICACION.AGENTE,CONTEO_GENERAL,starts_with("prop_")) %>%
  rename_with(~ gsub("^prop_count_", "", .x)) %>%  # Eliminar "prop_count_"
  rename_with(~ gsub(" ", "\n", .x)) 

motivos_por_agente <- registros_agentes %>%
  group_by(IDENTIFICACION.AGENTE) %>%
  summarise(CONTEO_GENERAL= n(),across(all_of(motivos), sum, .names = "count_{.col}"))  %>%
  #mutate(orden = match(IDENTIFICACION.AGENTE, comparendo_rechazado$IDENTIFICACION.AGENTE)) %>%
  #arrange(orden) %>%
  select(-CONTEO_GENERAL) %>%
  select(IDENTIFICACION.AGENTE,starts_with("count_")) %>%
  rename_with(~ gsub("^count_", "", .x)) %>%  # Eliminar "prop_count_"
  rename_with(~ gsub(" ", "\n", .x)) 

tabla_contingencia <- motivos_por_agente %>%
  select(-IDENTIFICACION.AGENTE) %>%  # Excluir la columna de agentes
  summarise(across(everything(), sum)) %>%  # Sumar por columnas
  mutate(IDENTIFICACION.AGENTE = "TOTAL")  # Agregar fila de total

tabla_contingencia <- motivos_por_agente %>%
  mutate(TOTAL_FILA = rowSums(select(., -IDENTIFICACION.AGENTE))) %>%  # Sumar filas
  bind_rows(tabla_contingencia)  # Unir con la fila de totales

total_general <- sum(tabla_contingencia[nrow(tabla_contingencia), -1], na.rm = TRUE)
tabla_contingencia[nrow(tabla_contingencia), "TOTAL_FILA"] <- total_general

#colnames(tabla_contingencia)[1] <- "IDENTIFICACION.AGENTE"

tabla_contingencia_percent <- tabla_contingencia %>%
  mutate(across(-IDENTIFICACION.AGENTE, ~ round((. / total_general) * 100,1))) %>% 
  mutate(orden = match(IDENTIFICACION.AGENTE, comparendo_rechazado$IDENTIFICACION.AGENTE)) %>%
  arrange(orden) %>%
  select(-orden) %>%
  mutate(across(-IDENTIFICACION.AGENTE, ~ as.numeric(gsub(",", ".", .)))) %>%
  mutate(across(where(is.numeric), ~ replace(., is.na(.), 0))) 

# Imprimir la tabla formateada
tabla_contingencia_percent %>%
  kable("html", escape = FALSE) %>%
  kable_styling(bootstrap_options = c("striped", "hover"))
IDENTIFICACION.AGENTE BAJA CALIDAD O FALLA EN FOTOGRAFIA NO APLICA INFRACCIÓN AL TIPO DE VEHICULO SUPERO INFRACCIONES IMPUESTAS POR DIA AL MISMO CONDUCTOR BAJA CALIDAD O FALLA EN VIDEO ERROR EN CARGUE DE FOTO O VIDEO NO SE EVIDENCIA INFRACCION O FALLA EN CAMARA ERROR EN IDENTIFICACIÓN DE PLACA EXCEDER TIEMPO LIMITE LEGAL PARA VALIDAR FACTORES AMBIENTALES FACTORES HUMANOS FORMATO NO DILIGENCIADO CORRECTAMENTE INCONSISTENCIA CARACTERISTICAS DEL VEHICULO INFORMACION INSUFICIENTE PARA GENERAR UN COMPARENDO NO REGISTRA DATOS SUFICIENTES VEHICULO FUERA DE RANGO DE VIDEO TOTAL_FILA
NA 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0 0.0 0.0 0.0 0.0 0 0.0 0.0 0.0
AGENTE 6 4.2 0.3 0.0 0.0 0.4 2.5 0.5 0 0.1 0.1 0.2 0.0 0 1.1 0.0 9.4
AGENTE 8 1.3 0.4 0.0 0.1 0.9 1.5 0.8 0 0.2 0.1 0.4 0.0 0 1.0 0.0 6.8
AGENTE 12 1.5 0.4 0.0 0.0 0.2 1.9 1.0 0 0.1 0.0 0.4 0.0 0 1.1 0.0 6.6
AGENTE 24 1.4 0.2 0.0 0.0 0.3 2.3 0.4 0 0.4 0.1 0.8 0.0 0 0.5 0.0 6.5
AGENTE 16 0.9 0.3 0.0 0.0 0.8 1.7 0.9 0 0.1 0.2 0.5 0.0 0 1.0 0.0 6.4
AGENTE 18 1.2 0.2 0.0 0.0 0.4 2.0 0.5 0 0.1 0.1 0.5 0.1 0 1.0 0.0 6.3
AGENTE 2 1.8 0.2 0.0 0.0 0.0 2.4 0.7 0 0.0 0.0 1.0 0.0 0 0.0 0.0 6.1
AGENTE 3 1.4 0.4 0.0 0.0 0.2 1.7 0.6 0 0.1 0.1 0.4 0.1 0 1.0 0.0 6.0
AGENTE 19 1.0 0.2 0.0 0.0 0.0 2.3 0.3 0 0.1 0.1 0.9 0.1 0 0.2 0.0 5.2
AGENTE 17 1.7 0.3 0.0 0.0 0.0 1.6 0.4 0 0.0 0.1 0.9 0.0 0 0.0 0.0 5.0
AGENTE 22 1.8 0.2 0.0 0.0 0.0 0.9 0.2 0 0.0 0.0 1.0 0.0 0 0.0 0.0 4.2
AGENTE 13 1.1 0.2 0.0 0.0 0.1 1.3 0.4 0 0.0 0.0 0.2 0.0 0 0.7 0.0 3.9
AGENTE 25 0.7 0.2 0.0 0.0 0.0 1.3 0.4 0 0.1 0.1 0.2 0.0 0 0.5 0.0 3.5
AGENTE 26 1.2 0.2 0.0 0.0 0.0 0.6 0.6 0 0.0 0.0 0.7 0.0 0 0.0 0.0 3.6
AGENTE 20 1.0 0.1 0.0 0.0 0.0 1.2 0.3 0 0.0 0.0 0.1 0.0 0 0.4 0.0 3.2
AGENTE 11 1.1 0.1 0.0 0.0 0.0 0.3 0.4 0 0.1 0.0 0.3 0.0 0 0.4 0.0 2.8
AGENTE 1 0.6 0.1 0.0 0.0 0.0 0.6 0.5 0 0.0 0.0 0.6 0.0 0 0.0 0.0 2.5
AGENTE 9 0.5 0.1 0.0 0.0 0.1 0.7 0.2 0 0.0 0.0 0.4 0.0 0 0.0 0.0 1.9
AGENTE 21 0.6 0.1 0.0 0.0 0.1 0.3 0.2 0 0.0 0.0 0.2 0.0 0 0.1 0.0 1.7
AGENTE 7 0.5 0.1 0.0 0.0 0.0 0.5 0.2 0 0.0 0.0 0.1 0.0 0 0.2 0.0 1.7
AGENTE 27 0.5 0.1 0.0 0.0 0.0 0.4 0.2 0 0.0 0.0 0.3 0.0 0 0.0 0.0 1.5
AGENTE 29 0.5 0.1 0.0 0.0 0.0 0.5 0.1 0 0.0 0.1 0.2 0.0 0 0.0 0.0 1.5
AGENTE 23 0.9 0.1 0.0 0.0 0.0 0.0 0.1 0 0.0 0.0 0.2 0.0 0 0.0 0.0 1.3
AGENTE 5 0.7 0.0 0.0 0.0 0.0 0.0 0.0 0 0.0 0.0 0.1 0.0 0 0.0 0.0 0.9
AGENTE 10 0.2 0.0 0.0 0.0 0.0 0.1 0.1 0 0.0 0.0 0.1 0.0 0 0.0 0.0 0.5
AGENTE 15 0.2 0.0 0.0 0.0 0.0 0.0 0.0 0 0.0 0.0 0.0 0.0 0 0.0 0.0 0.3
AGENTE 28 0.0 0.0 0.0 0.0 0.0 0.1 0.1 0 0.0 0.0 0.1 0.0 0 0.0 0.0 0.4
AGENTE 14 0.1 0.0 0.0 0.0 0.0 0.0 0.0 0 0.0 0.0 0.0 0.0 0 0.0 0.0 0.2
AGENTE 4 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0 0.0 0.0 0.0 0.0 0 0.0 0.0 0.0
TOTAL 28.7 4.5 0.1 0.3 3.8 28.9 9.8 0 1.7 1.3 10.9 0.5 0 9.5 0.1 100.0