AVISO IMPORTANTE!

Originalmente, la variable tipo de líquidos era de naturaleza cualitativa nominal,ya que solo listaba nombres de fluidos sin un orden inherente. Para enriquecer el análisis de seguridad, se realizó una transformación a variable ordinal aplicando un criterio de volatilidad y riesgo de explosión.

Se reclasificaron los fluidos en tres niveles jerárquicos:

Nivel 1: Bajo riesgo (CRUDO / PETRÓLEO).

Nivel 2: Medio riesgo (DIESEL / KEROSENE, GASOLINA, BIODIESEL / OTROS, QUÍMICOS).

Nivel 3: Alto riesgo (GASES LICUADOS, LÍQUIDO ALTAMENTE VOLÁTIL, OTROS COMBUSTIBLES)

1 .Cargar datos

Importamos el archivo “dataset proyecto.csv” desde una ruta local y lo almacena en el objeto datos.

datos <- read.csv2("C:/Users/chipr/Downloads/dataset proyecto.csv")

# Librerías
library(dplyr)
## Warning: package 'dplyr' was built under R version 4.5.2
## 
## Adjuntando el paquete: 'dplyr'
## The following objects are masked from 'package:stats':
## 
##     filter, lag
## The following objects are masked from 'package:base':
## 
##     intersect, setdiff, setequal, union
library(knitr)
## Warning: package 'knitr' was built under R version 4.5.2
library(kableExtra)
## Warning: package 'kableExtra' was built under R version 4.5.2
## 
## Adjuntando el paquete: 'kableExtra'
## The following object is masked from 'package:dplyr':
## 
##     group_rows
library(ggplot2)




# Limpieza y asignación de niveles de riesgo
datos_liquidos <- datos %>%
  mutate(Tipo_Clean = case_when(
    is.na(Liquid.Type) | Liquid.Type == "" ~ "CRUDO / PETRÓLEO",
    grepl("CRUDE", Liquid.Type, ignore.case = TRUE) ~ "CRUDO / PETRÓLEO",
    grepl("OIL", Liquid.Type, ignore.case = TRUE) & 
      !grepl("GASOLINE|DIESEL", Liquid.Type, ignore.case = TRUE) ~ "CRUDO / PETRÓLEO",
    grepl("CO2", Liquid.Type, ignore.case = TRUE) ~ "CRUDO / PETRÓLEO",
    grepl("DIESEL", Liquid.Type, ignore.case = TRUE) ~ "DIESEL / KEROSENE",
    grepl("KEROSENE", Liquid.Type, ignore.case = TRUE) ~ "DIESEL / KEROSENE",
    grepl("JET", Liquid.Type, ignore.case = TRUE) ~ "DIESEL / KEROSENE",
    grepl("GASOLINE", Liquid.Type, ignore.case = TRUE) ~ "GASOLINA",
    grepl("PETROL", Liquid.Type, ignore.case = TRUE) ~ "GASOLINA",
    grepl("LPG", Liquid.Type, ignore.case = TRUE) ~ "GASES LICUADOS",
    grepl("PROPANE", Liquid.Type, ignore.case = TRUE) ~ "GASES LICUADOS",
    grepl("BUTANE", Liquid.Type, ignore.case = TRUE) ~ "GASES LICUADOS",
    grepl("NGL", Liquid.Type, ignore.case = TRUE) ~ "GASES LICUADOS",
    grepl("NATURAL GAS", Liquid.Type, ignore.case = TRUE) ~ "GASES LICUADOS",
    grepl("HVL", Liquid.Type, ignore.case = TRUE) ~ "LÍQUIDO ALTAMENTE VOLÁTIL",
    grepl("VOLATILE", Liquid.Type, ignore.case = TRUE) ~ "LÍQUIDO ALTAMENTE VOLÁTIL",
    grepl("BIO", Liquid.Type, ignore.case = TRUE) ~ "BIODIESEL / OTROS",
    grepl("ETHANOL", Liquid.Type, ignore.case = TRUE) ~ "BIODIESEL / OTROS",
    grepl("AMMONIA", Liquid.Type, ignore.case = TRUE) ~ "QUÍMICOS",
    TRUE ~ "OTROS COMBUSTIBLES"
  )) %>%
  mutate(Nivel_Riesgo = case_when(
    Tipo_Clean == "CRUDO / PETRÓLEO" ~ 1,
    Tipo_Clean %in% c("DIESEL / KEROSENE", "GASOLINA", "BIODIESEL / OTROS", "QUÍMICOS") ~ 2,
    Tipo_Clean %in% c("GASES LICUADOS", "LÍQUIDO ALTAMENTE VOLÁTIL", "OTROS COMBUSTIBLES") ~ 3,
    TRUE ~ 0
  ))

2 .Tabla de Cantidad

Extraemos la variable tipo de líquidos, omitimos las celdas en blanco o valores iguales a cero y verificamos el tamaño muestral. En la tabla de distribución de frecuencias de la variable Tipo de Líquido, el número de clases se determinó mediante la regla de Sturges y el ancho de clase se calculó a partir del rango total de los datos, asegurando una cobertura completa desde el valor mínimo hasta el valor máximo registrado en la muestra.

TDF_agrupada <- datos_liquidos %>%
  count(Nivel_Riesgo, Tipo_Clean, name = "ni") %>%
  arrange(Nivel_Riesgo, desc(ni))

ni_total <- sum(TDF_agrupada$ni)

TDF_agrupada$hi <- (TDF_agrupada$ni / ni_total) * 100
TDF_agrupada$hi <- sprintf("%.2f", round(TDF_agrupada$hi, 2))

Sumatoria <- data.frame(
  Nivel_Riesgo = "",
  Tipo_Clean = "TOTAL",
  ni = ni_total,
  hi = "100.00"
)

TDF_final <- rbind(TDF_agrupada, Sumatoria)
colnames(TDF_final) <- c("Nivel Riesgo", "Tipo de Líquido", "ni", "hi (%)")

kable(TDF_final, align = 'c', 
      caption = "Tabla 1: Frecuencia de Tipos de Líquido por Nivel de Riesgo") %>%
  kable_styling(full_width = FALSE, position = "center", 
                bootstrap_options = c("striped", "hover", "condensed")) %>%
  row_spec(nrow(TDF_final), bold = TRUE, background = "#f2f2f2") %>%
  row_spec(which(TDF_final$`Nivel Riesgo` == "3"), bold = TRUE)
Tabla 1: Frecuencia de Tipos de Líquido por Nivel de Riesgo
Nivel Riesgo Tipo de Líquido ni hi (%)
1 CRUDO / PETRÓLEO 1436 51.38
2 GASOLINA 939 33.60
2 BIODIESEL / OTROS 2 0.07
3 LÍQUIDO ALTAMENTE VOLÁTIL 418 14.96
TOTAL 2795 100.00

3 .Cantidad absoluta local de Accidentes según la Volatilidad del Líquido

En la tabla de distribución de frecuencias de esta variable, se aplicó una clasificación por nivel de riesgo (Bajo, Medio y Alto) basada en la volatilidad de los componentes, evidenciando que la mayor cantidad de registros corresponde al Crudo/Petróleo (riesgo bajo) con cerca de 2795 casos, seguido por combustibles de riesgo medio como los Productos Refinados, mientras que las sustancias de alta volatilidad y riesgo elevado, como los HVL, muestran la menor incidencia de accidentes en la muestra estudiada.

datos_grafico_local <- datos_liquidos %>%
  mutate(Nivel_Riesgo_Texto = case_when(
    Nivel_Riesgo == 1 ~ "1. Bajo",
    Nivel_Riesgo == 2 ~ "2. Medio",
    Nivel_Riesgo == 3 ~ "3. Alto",
    TRUE ~ "0. Desconocido"
  )) %>%
  count(Nivel_Riesgo_Texto, Tipo_Clean, name = "ni")

datos_grafico_local$Nivel_Riesgo_Texto <- factor(
  datos_grafico_local$Nivel_Riesgo_Texto, 
  levels = c("1. Bajo", "2. Medio", "3. Alto")
)

ggplot(datos_grafico_local, aes(x = reorder(Tipo_Clean, -ni), y = ni, fill = Nivel_Riesgo_Texto)) + 
  geom_bar(stat = "identity", width = 0.75, color = "black") + 
  scale_fill_manual(values = c(
    "1. Bajo" = "#AED6F1",  
    "2. Medio" = "#3498DB",  
    "3. Alto" = "#154360"    
  )) +
  labs(
    title = "Gráfica N1: Accidentes por Tipo de Líquido - Distribución Local",
    x = "Tipo de Líquido",
    y = "Cantidad",
    fill = "Nivel de Riesgo"
  ) +
  theme_light() +
  theme(
    axis.text.x = element_text(angle = 45, hjust = 1, color = "black"),
    legend.position = "top"
  )

4 .Cantidad Absoluta Global de Accidentes por Tipo de Fluido

Extraemos la variable tipo de líquidos, omitimos las celdas en blanco o valores iguales a cero y verificamos el tamaño muestral para determinar la frecuencia absoluta de accidentes tanto en el ámbito local como global.

maximo_global <- max(table(datos_liquidos$Tipo_Clean))

datos_grafico_global <- datos_liquidos %>%
  mutate(Nivel_Riesgo_Texto = case_when(
    Nivel_Riesgo == 1 ~ "1. Bajo",
    Nivel_Riesgo == 2 ~ "2. Medio",
    Nivel_Riesgo == 3 ~ "3. Alto",
    TRUE ~ "0. Desconocido"
  )) %>%
  count(Nivel_Riesgo_Texto, Tipo_Clean, name = "ni")

datos_grafico_global$Nivel_Riesgo_Texto <- factor(
  datos_grafico_global$Nivel_Riesgo_Texto, 
  levels = c("1. Bajo", "2. Medio", "3. Alto")
)

ggplot(datos_grafico_global, aes(x = reorder(Tipo_Clean, -ni), y = ni, fill = Nivel_Riesgo_Texto)) + 
  geom_bar(stat = "identity", width = 0.7, color = "black") + 
  scale_fill_manual(values = c(
    "1. Bajo" = "#AED6F1",   
    "2. Medio" = "#3498DB",  
    "3. Alto" = "#154360"    
  )) +
  scale_y_continuous(
    limits = c(0, maximo_global),        
    breaks = seq(0, maximo_global, by = round(maximo_global/5, -1))
  ) +
  labs(
    title = "Gráfica N2: Accidentes por Tipo de Líquido - Distribución Global",
    x = "Tipo de Líquido",
    y = "Cantidad",
    fill = "Nivel de Riesgo"
  ) +
  theme_light() +
  theme(
    axis.text.x = element_text(angle = 45, hjust = 1, color = "black"),
    legend.position = "top"
  )

5 .Porcentaje global de Accidentes por Tipo de Líquido

Aunque parezca contradictorio que el mayor número de accidentes ocurra con sustancias de “bajo riesgo”, esto suele indicar que el volumen de transporte y manipulación del crudo es masivamente superior al de gases altamente volátiles. Es un recordatorio de que, estadísticamente, la mayoría de los problemas ocurren donde hay más actividad, incluso si la sustancia es más estable.

datos_hi_global <- datos_liquidos %>%
  mutate(Nivel_Riesgo_Texto = case_when(
    Nivel_Riesgo == 1 ~ "1. Bajo",
    Nivel_Riesgo == 2 ~ "2. Medio",
    Nivel_Riesgo == 3 ~ "3. Alto",
    TRUE ~ "0. Desconocido"
  )) %>%
  count(Nivel_Riesgo_Texto, Tipo_Clean, name = "ni") %>%
  mutate(hi_pct = (ni / sum(ni)) * 100)

datos_hi_global$Nivel_Riesgo_Texto <- factor(
  datos_hi_global$Nivel_Riesgo_Texto, 
  levels = c("1. Bajo", "2. Medio", "3. Alto")
)

ggplot(datos_hi_global, aes(x = reorder(Tipo_Clean, -hi_pct), y = hi_pct, fill = Nivel_Riesgo_Texto)) +
  geom_bar(stat = "identity", width = 0.7, color = "black") +
  scale_fill_manual(values = c(
    "1. Bajo" = "#AED6F1",
    "2. Medio" = "#3498DB",  
    "3. Alto" = "#154360"    
  )) +
  scale_y_continuous(limits = c(0, 100), breaks = seq(0, 100, by = 20)) +
  labs(
    title = "Gráfica 3: Porcentaje global de Accidentes por Tipo de Líquido",
    x = "Tipo de Líquido",
    y = "Porcentaje (%)",
    fill = "Nivel de Riesgo"
  ) +
  theme_classic() +
  theme(
    axis.text.x = element_text(angle = 45, hjust = 1, color = "black"),
    legend.position = "top"
  )

6 .Porcentaje local de Incidentes Clasificada por tipo del Material

Extraemos la variable tipo de líquidos, omitimos valores nulos o ceros y determinamos la frecuencia mediante la regla de Sturges. El análisis muestra que el Crudo/Petróleo (riesgo bajo) concentra más del 50% de los incidentes a nivel local y global. Las sustancias de alta volatilidad registran la menor cantidad de accidentes, vinculando la siniestralidad al volumen de operación manejado.

datos_hi_local <- datos_liquidos %>%
  mutate(Nivel_Riesgo_Texto = case_when(
    Nivel_Riesgo == 1 ~ "1. Bajo",
    Nivel_Riesgo == 2 ~ "2. Medio",
    Nivel_Riesgo == 3 ~ "3. Alto",
    TRUE ~ "0. Desconocido"
  )) %>%
  count(Nivel_Riesgo_Texto, Tipo_Clean, name = "ni") %>%
  mutate(hi_pct = (ni / sum(ni)) * 100)

datos_hi_local$Nivel_Riesgo_Texto <- factor(
  datos_hi_local$Nivel_Riesgo_Texto, 
  levels = c("1. Bajo", "2. Medio", "3. Alto")
)

ggplot(datos_hi_local, aes(x = reorder(Tipo_Clean, -hi_pct), y = hi_pct, fill = Nivel_Riesgo_Texto)) +
  geom_bar(stat = "identity", width = 0.7, color = "black") +
  scale_fill_manual(values = c(
    "1. Bajo" = "#AED6F1",
    "2. Medio" = "#3498DB",  
    "3. Alto" = "#154360"    
  )) +
  labs(
    title = "Gráfica 4: Porcentaje local de Accidentes por Tipo de Líquido",
    x = "Tipo de Líquido",
    y = "Porcentaje (%)",
    fill = "Nivel de Riesgo"
  ) +
  theme_classic() +
  theme(
    axis.text.x = element_text(angle = 45, hjust = 1, color = "black"),
    legend.position = "top"
  )

7 .Diagrama circular

El diagrama circular de la variable tipo de líquidos resalta visualmente la hegemonía del Crudo/Petróleo, que ocupa más de la mitad de la superficie total,reflejando su predominancia en la siniestralidad. Los sectores restantes se distribuyen entre combustibles de riesgo medio y gases de alta volatilidad, evidenciando que la gran mayoría de los incidentes se concentran en una sola categoría operativa. Esta representación permite confirmar que, a pesar de su bajo riesgo intrínseco, el volumen de manejo de este fluido es el factor determinante en la frecuencia de los accidentes.

datos_grafico_pie <- datos_liquidos %>%
  count(Tipo_Clean, name = "ni") %>%
  mutate(hi_pct = round((ni / sum(ni)) * 100, 1)) %>%
  mutate(
    Nivel_Riesgo = case_when(
      Tipo_Clean %in% c("GASES LICUADOS", "LÍQUIDO ALTAMENTE VOLÁTIL", "OTROS COMBUSTIBLES") ~ "Alto",
      Tipo_Clean %in% c("DIESEL / KEROSENE", "GASOLINA", "BIODIESEL / OTROS", "QUÍMICOS") ~ "Medio",
      Tipo_Clean == "CRUDO / PETRÓLEO" ~ "Bajo",
      TRUE ~ "Otros"
    ),
    Nivel_Riesgo = factor(Nivel_Riesgo, levels = c("Alto", "Medio", "Bajo"))
  )

colores_riesgo_map <- c(
  "CRUDO / PETRÓLEO" = "#AED6F1",
  "DIESEL / KEROSENE" = "#3498DB",
  "GASOLINA" = "#3498DB",
  "BIODIESEL / OTROS" = "#3498DB",
  "QUÍMICOS" = "#3498DB",
  "GASES LICUADOS" = "#154360",
  "LÍQUIDO ALTAMENTE VOLÁTIL" = "#154360",
  "OTROS COMBUSTIBLES" = "#154360"
)

colores_niveles <- c(
  "Alto" = "#154360",
  "Medio" = "#3498DB",
  "Bajo" = "#AED6F1"
)

ggplot(datos_grafico_pie, aes(x = "", y = hi_pct, fill = Tipo_Clean)) +
  geom_bar(stat = "identity", width = 1, color = "black", linewidth = 1) +
  geom_point(aes(color = Nivel_Riesgo), alpha = 0, size = 0) +
  coord_polar("y", start = 0) +
  geom_text(aes(label = paste0(hi_pct, "%")), 
            position = position_stack(vjust = 0.5), 
            color = "white", size = 3.5, fontface = "bold") +
  scale_fill_manual(values = colores_riesgo_map) +
  scale_color_manual(values = colores_niveles) + 
  labs(
    title = "Gráfica 5: Distribución circular por Tipo de Líquido y Nivel de Riesgo",
    fill = "Tipo de Líquido",
    color = "Nivel de Riesgo" 
  ) +
  guides(
    fill = guide_legend(order = 1),
    color = guide_legend(order = 2, override.aes = list(alpha = 1, size = 5, shape = 15))
  ) +
  theme_void() +
  theme(
    plot.title = element_text(hjust = 0.5, face = "bold", margin = margin(b = 10)),
    legend.position = "right"
  )

8 .Indicadores estadísticos

Los indicadores estadísticos de la variable tipo de líquidos muestran una distribución con una moda contundente en la categoría Crudo/Petróleo, la cual representa la mayor frecuencia absoluta con aproximadamente 2795 registros.Al analizar la concentración de los datos, se observa que el riesgo bajo domina la muestra con un peso superior al 50%, mientras que las medidas de dispersión reflejan una variabilidad reducida hacia las categorías de riesgo alto, confirmando una asimetría donde la siniestralidad se agrupa en fluidos de gran volumen operativo y baja volatilidad.

media_riesgo <- mean(datos_liquidos$Nivel_Riesgo, na.rm = TRUE)
mediana_riesgo <- median(datos_liquidos$Nivel_Riesgo, na.rm = TRUE)

frecuencias_riesgo <- TDF_agrupada %>%
  group_by(Nivel_Riesgo) %>%
  summarise(Total_ni = sum(ni)) %>%
  arrange(desc(Total_ni))

moda_riesgo <- frecuencias_riesgo$Nivel_Riesgo[1]

tabla_tendencia <- data.frame(
  Estadístico = c("Media", "Mediana", "Moda"),
  Valor = c(round(media_riesgo, 2), mediana_riesgo, moda_riesgo),
  Interpretación = c(
    "Promedio del nivel de riesgo de los accidentes (Escala 1 al 3)",
    "Punto central: el 50% de los incidentes son de este nivel o menor",
    "Nivel de Riesgo que ocurre con mayor frecuencia"
  )
)

kable(tabla_tendencia, align = c('l', 'c', 'l'), 
      caption = "Tabla 2: Medidas de Tendencia Central - Accidentes por Tipo de Líquido") %>%
  kable_styling(full_width = FALSE, position = "center", 
                bootstrap_options = c("striped", "hover", "condensed")) %>%
  row_spec(1:3, bold = TRUE, background = "#ffeeba")
Tabla 2: Medidas de Tendencia Central - Accidentes por Tipo de Líquido
Estadístico Valor Interpretación
Media 1.64 Promedio del nivel de riesgo de los accidentes (Escala 1 al 3)
Mediana 1.00 Punto central: el 50% de los incidentes son de este nivel o menor
Moda 1.00 Nivel de Riesgo que ocurre con mayor frecuencia

9 . Conclusion

El análisis de las medidas de tendencia central revela que la siniestralidad está fuertemente concentrada en el Nivel de Riesgo 1 (Bajo), correspondiente al manejo de CRUDO / PETRÓLEO, el cual representa tanto la moda (1.00) como la mediana (1.00) de la distribución. Esto confirma que al menos el 50% de los incidentes registrados pertenecen a la categoría de menor criticidad inmediata. No obstante, la media aritmética se sitúa en 1.64, un valor superior a la mediana. Esto evidencia una distribución con asimetría positiva.