Justificación de la variable

Para entender de forma sencilla por qué el “Mes del accidente” es una variable cuantitativa discreta, imaginen el año como una escalera con 12 escalones fijos, en lugar de un río que fluye sin parar. Es cuantitativa porque podemos representarla numéricamente (asignando valores del 1 al 12) para realizar cálculos matemáticos, como analizar la frecuencia de incidentes o calcular su promedio. Y es discreta porque, al registrar únicamente el mes, el dato da saltos enteros: pasamos de un mes al siguiente como unidades completas (del mes 1 al mes 2), sin tomar en cuenta las fracciones de tiempo que existen en el medio (estadísticamente no registramos un “mes 1.5”). Por lo tanto, al capturar este dato, estamos registrando un punto específico y contable dentro de una secuencia de meses enteros.

1 Cargar datos

Todo análisis riguroso comienza con la validación de la materia prima. En esta fase, se estructuran los registros crudos de los apagados para convertirlos en un formato temporal operable (limpieza, parseo de fechas y extracción de componentes temporales) que garantice la integridad técnica del estudio.

database <- read.csv("database-_1_.csv", header = TRUE, sep = ",", dec = ".", check.names = FALSE)
raw_dates<- database$`Shutdown Date/Time`
raw_dates <- raw_dates[raw_dates != ""]
raw_dates <- na.omit(raw_dates)
fechas_obj <- as.POSIXct(raw_dates, format = "%m/%d/%Y")
amperaje <- as.numeric(fechas_obj)
amperaje <- na.omit(amperaje)
fechas_obj <- fechas_obj[!is.na(amperaje)]

2 Tabla de Frecuencia

Para comprender la dinámica de los cortes, es imperativo transicionar de datos temporales continuos a intervalos discretos. Esta sección consolida la agrupación cronológica mediante clases, sentando las bases matemáticas para la evaluación de densidades y probabilidades.

# Cargar librerías necesarias
library(dplyr)
library(rmarkdown)

# 1. CARGA DE DATOS
datos <- read.csv("database-_1_.csv", stringsAsFactors = FALSE)

# 2. EXTRACCIÓN Y LIMPIEZA DE LA VARIABLE (MES)
fechas <- as.POSIXct(datos$Accident.Date.Time, format="%m/%d/%Y %H:%M")
meses_limpios <- as.numeric(format(fechas, "%m"))
meses_limpios <- meses_limpios[!is.na(meses_limpios)]

# 3. CREACIÓN DE LA TABLA DE FRECUENCIAS DISCRETA
tabla_base <- table(meses_limpios)
ni <- as.vector(tabla_base)

# Esta será tu única columna para el mes (1, 2, 3... hasta 12)
Mes <- names(tabla_base) 

hi <- round(ni / sum(ni) * 100, 2)

# Ajuste por pérdida de decimales para asegurar que sume 100%
diferencia <- 100 - sum(hi)
if(diferencia != 0){
  indice_max <- which.max(ni)
  hi[indice_max] <- hi[indice_max] + diferencia
}

# 4. CÁLCULO DE FRECUENCIAS ACUMULADAS
Ni_asc <- cumsum(ni)
Ni_dsc <- rev(cumsum(rev(ni)))
Hi_asc <- cumsum(hi)            
Hi_dsc <- rev(cumsum(rev(hi)))

# 5. CONSTRUCCIÓN DEL DATAFRAME FINAL
TDFMesFin <- data.frame(
  "Mes" = Mes, 
  "ni" = ni, 
  "hi (%)" = hi, 
  "Ni Asc" = Ni_asc, 
  "Ni Dsc" = Ni_dsc, 
  "Hi Asc" = Hi_asc, 
  "Hi Dsc" = Hi_dsc,
  check.names = FALSE
)

# 6. MOSTRAR TABLA 
paged_table(TDFMesFin, options = list(rows.print = 6))

3 Histograma de Cantidad Absoluta

La visualización macroscópica permite identificar el volumen total de incidencias. Este apartado despliega la distribución temporal completa, revelando visualmente las tendencias estructurales y la concentración del fenómeno a lo largo de todo el periodo de estudio.

# Cargar la librería necesaria para graficar
library(ggplot2)

# Convertimos 'Mes' a factor para asegurar que se ordene correctamente del 1 al 12
TDFMesFin$Mes <- factor(TDFMesFin$Mes, levels = as.character(1:12))

total_apagones <- sum(TDFMesFin$ni)

p_ni <- ggplot(TDFMesFin, aes(x = Mes, y = ni)) +
  geom_col(fill = "steelblue", color = "black", alpha = 0.8, linewidth = 0.5) +
  scale_y_continuous(expand = expansion(mult = c(0, 0.05))) +
  labs(
    title = "Gráfica No 1: Distribución de los apagados locales",
    x = "Mes del Año",
    y = "Cantidad"
  ) +
  theme_classic() +
  theme(
    plot.title = element_text(hjust = 0.5, face = "bold", size = 13),
    plot.subtitle = element_text(hjust = 0.5, color = "gray40"),
    axis.text.x = element_text(angle = 0, hjust = 0.5, color = "black"),
    axis.text.y = element_text(color = "black"),
    axis.line = element_line(linewidth = 0.5, color = "black")
  )

print(p_ni)

4 Histograma de Cantidad Absoluta

Al aislar ventanas temporales críticas, se incrementa la resolución del análisis. Aquí se evalúa el comportamiento volumétrico en intervalos específicos de alta relevancia operativa (ej. el mes más crítico) para contrastarlo con el histórico general.

# Cargar la librería necesaria para graficar
library(ggplot2)

# Convertimos 'Mes' a factor para asegurar que se ordene correctamente del 1 al 12
TDFMesFin$Mes <- factor(TDFMesFin$Mes, levels = as.character(1:12))

total_apagones <- sum(TDFMesFin$ni)

p_ni <- ggplot(TDFMesFin, aes(x = Mes, y = ni)) +
  geom_col(fill = "steelblue", color = "black", alpha = 0.8, linewidth = 0.5) +
  scale_y_continuous(limits = c(0, 2795), expand = expansion(mult = c(0, 0.05))) +
  labs(
    title = "Gráfica No 2: Distribución de pagados glogables",
    x = "Mes del Año",
    y = "Cantidad"
  ) +
  theme_classic() +
  theme(
    plot.title = element_text(hjust = 0.5, face = "bold", size = 13),
    plot.subtitle = element_text(hjust = 0.5, color = "gray40"),
    axis.text.x = element_text(angle = 0, hjust = 0.5, color = "black"),
    axis.text.y = element_text(color = "black"),
    axis.line = element_line(linewidth = 0.5, color = "black")
  )

print(p_ni)

5 Histograma de Cantidad Relativa

Trascendiendo el conteo absoluto, este enfoque normaliza los datos para expresar el peso proporcional de cada intervalo. Es una herramienta crucial para entender la densidad de probabilidad de ocurrencia de un apagado en el panorama general.

# Cargar la librería si no está cargada
library(ggplot2)

# Asegurarnos de que el 'Mes' esté ordenado del 1 al 12
TDFMesFin$Mes <- factor(TDFMesFin$Mes, levels = as.character(1:12))

p_hi <- ggplot(TDFMesFin, aes(x = Mes, y = `hi (%)`)) +
  geom_col(fill = "steelblue", color = "black", alpha = 0.8, linewidth = 0.5) +
  # Ya no usamos scale_x_continuous porque el Mes es texto discreto
  scale_y_continuous(limits = c(0, 100),
                     expand = expansion(mult = c(0, 0.05)),
                     labels = function(x) paste0(x, "%")) + 
  labs(title = "Gráfica 3: Porcentaje apagado global",
       x = "Mes",
       y = "Porcentaje") +
  theme_classic() +
  theme(
    plot.title = element_text(hjust = 0.5, face = "bold", size = 13),
    axis.text.x = element_text(angle = 0, hjust = 0.5, color = "black"), # Ángulo 0
    axis.text.y = element_text(color = "black"),
    axis.line = element_line(linewidth = 0.5, color = "black")
  )

print(p_hi)

6 Histograma de Cantidad Relativa

Mediante el escalado probabilístico en segmentos temporales acotados, este análisis permite verificar si las dinámicas locales de los apagados obedecen al mismo modelo de probabilidad que rige la tendencia histórica.

# Cargar la librería si no está cargada
library(ggplot2)

# Asegurarnos de que el 'Mes' se ordene correctamente del 1 al 12
TDFMesFin$Mes <- factor(TDFMesFin$Mes, levels = as.character(1:12))

p_hi_barras <- ggplot(TDFMesFin, aes(x = Mes, y = `hi (%)`)) +
  geom_col(fill = "steelblue", color = "black", alpha = 0.8, linewidth = 0.5) +
  # Se elimina scale_x_continuous porque los meses ya son texto ordenado
  scale_y_continuous(labels = function(x) paste0(x, "%"),
                     expand = expansion(mult = c(0, 0.05))) +
  labs(title = "Gráfica 4: Porcentaje apagado local",
       x = "Mes",
       y = "Porcentaje") +
  theme_classic() +
  theme(
    plot.title = element_text(hjust = 0.5, face = "bold", size = 13),
    axis.text.x = element_text(angle = 0, hjust = 0.5, color = "black"), # Ángulo 0 para texto horizontal
    axis.text.y = element_text(color = "black"),
    axis.line = element_line(linewidth = 0.5, color = "black")
  )

print(p_hi_barras)

7 Ojivas Combinadas

El estudio de la progresión acumulativa es vital para establecer umbrales temporales. Esta gráfica ilustra la suma secuencial de los eventos, evidenciando la velocidad y el ritmo con el que se acumulan los apagados en el tiempo.

# Cargar librerías necesarias
library(ggplot2)
library(scales)

# Para trazar líneas, necesitamos que el Mes sea interpretado como número (1 al 12)
TDFMesFin$Mes_num <- as.numeric(as.character(TDFMesFin$Mes))

p_ojiva_replicada <- ggplot(TDFMesFin) +
  # Usamos la columna de mes numérica y la frecuencia acumulada Ascendente
  geom_line(aes(x = Mes_num, y = `Ni Asc`, color = "Ascendente", linetype = "Ascendente"), linewidth = 0.8) +
  geom_point(aes(x = Mes_num, y = `Ni Asc`, color = "Ascendente"), size = 2) +
  
  # Usamos la columna de mes numérica y la frecuencia acumulada Descendente
  geom_line(aes(x = Mes_num, y = `Ni Dsc`, color = "Descendente", linetype = "Descendente"), linewidth = 0.8) +
  geom_point(aes(x = Mes_num, y = `Ni Dsc`, color = "Descendente"), size = 2) +
  
  # Forzamos que en el eje X aparezcan los números exactos del 1 al 12
  scale_x_continuous(breaks = 1:12) +
  
  scale_color_manual(name = NULL, 
                     values = c("Ascendente" = "black", "Descendente" = "blue")) +
  scale_linetype_manual(name = NULL, 
                        values = c("Ascendente" = "longdash", "Descendente" = "solid")) +
  labs(title = "Gráfica 5:Distribución acumulada del mes de apagado",
       x = "Mes",
       y = "Cantidad") +
  theme_bw() + 
  theme(
    plot.title = element_text(hjust = 0.5, face = "bold", size = 14),
    legend.position = c(0.85, 0.85),  
    legend.background = element_rect(color = "black", fill = "white", linewidth = 0.5), 
    legend.key = element_blank(),
    panel.grid.minor = element_blank(),
    axis.text = element_text(color = "black"),
    axis.title.y = element_text(angle = 90, vjust = 0.5)
  )

print(p_ojiva_replicada)

8 Diagrama de caja

Más allá de las frecuencias, es fundamental evaluar la variabilidad posicional de los eventos. El diagrama de caja desentraña la estacionalidad, identificando la concentración de la “hora de apagado” y su dispersión según días o meses.

boxplot(meses_limpios, 
        horizontal = TRUE, 
        col = "skyblue",            
        main = "Gráfica 7: Distribución de apagados por Mes",
        xlab = "Mes del Año",
        xaxt = "n") 
axis(1, at = 1:12, labels = 1:12, las = 1)
grid(nx = NULL, ny = NA, col = "lightgray", lty = "dotted")

9 Tabla Estadístico

La cuantificación objetiva requiere robustez matemática. En este apartado se calculan los parámetros exactos de centralización, dispersión y forma para caracterizar analíticamente el perfil temporal de las interrupciones.

library(e1071) 
library(knitr) 

# Asumimos que el vector 'meses_limpios' ya está cargado de los pasos anteriores

# 1. Rango (Mínimo y Máximo)
ri <- min(meses_limpios)
rs <- max(meses_limpios)
print(paste("Mínimo:", ri))
## [1] "Mínimo: 1"
print(paste("Máximo:", rs))
## [1] "Máximo: 12"
# 2. Mediana 
mediana <- median(meses_limpios)
print(paste("Mediana:", mediana))
## [1] "Mediana: 6"
# 3. Media Aritmética 
media_aritmetica <- mean(meses_limpios)
print(paste("Media:", round(media_aritmetica, 0)))
## [1] "Media: 6"
# 4. Moda 
t <- table(meses_limpios)
Mo <- as.numeric(names(t)[which.max(t)]) 
print(paste("Moda:", Mo))
## [1] "Moda: 1"
# 5. Desviación Estándar 
# Al ser meses, la desviación se expresa directamente en "meses"
desviacion_estandar <- sd(meses_limpios)
print(paste("Desviación Estándar:", round(desviacion_estandar, 2), "meses"))
## [1] "Desviación Estándar: 3.48 meses"
# 6. Coeficiente de Variabilidad
coeficiente_variabilidad <- (desviacion_estandar / media_aritmetica) * 100
print(paste("CV:", round(coeficiente_variabilidad, 2), "%"))
## [1] "CV: 55.51 %"
# 7. Asimetría (Skewness)
As <- skewness(meses_limpios)
print(paste("Asimetría:", round(As, 2)))
## [1] "Asimetría: 0.08"
# 8. Curtosis
curtosis_val <- kurtosis(meses_limpios)
print(paste("Curtosis:", round(curtosis_val, 2)))
## [1] "Curtosis: -1.22"
# --- PREPARACIÓN DE LA TABLA ---
Variable <- "Mes del Accidente"
S_texto <- paste(round(desviacion_estandar, 2), "meses") # Desviación en meses

Tabla_indicadores <- data.frame(
  Variable,
  ri,                               # Mínimo
  rs,                               # Máximo
  round(media_aritmetica, 0),       # Media 
  mediana,                          # Mediana
  Mo,                               # Moda
  S_texto,                          # Desviación
  round(coeficiente_variabilidad, 2), 
  round(As, 2), 
  round(curtosis_val, 2)
)

colnames(Tabla_indicadores) <- c("Variable","Mínimo","Máximo","x","Me","Mo","S","Cv (%)","As","K")

# Imprimir Tabla
kable(Tabla_indicadores, format = "markdown", caption = "Tabla No. 2: Indicadores estadísticos de la variable Mes del Accidente.")
Tabla No. 2: Indicadores estadísticos de la variable Mes del Accidente.
Variable Mínimo Máximo x Me Mo S Cv (%) As K
Mes del Accidente 1 12 6 6 1 3.48 meses 55.51 0.08 -1.22

10 Valores Atípicos

Esta sección se enfoca en los ‘Cisnes Negros’ del dataset: eventos de baja frecuencia pero impacto catastrófico. Identificar los valores atípicos permite aislar aquellos fallos críticos de seguridad donde la evacuación superó los rangos normales, siendo esta la información más valiosa para el diseño de planes de contingencia y gestión de crisis.

# Usamos boxplot.stats sobre nuestro vector numérico de meses
stats_outliers <- boxplot.stats(meses_limpios)$out

# Contar los valores atípicos
num_outliers <- length(stats_outliers)
print(paste("Cantidad de meses atípicos:", num_outliers))
## [1] "Cantidad de meses atípicos: 0"
# Obtener Mínimo y Máximo Outlier (si existen)
# Usamos 'if' para evitar errores si num_outliers es 0
minimooutliers <- if(num_outliers > 0) min(stats_outliers) else NA
maximooutliers <- if(num_outliers > 0) max(stats_outliers) else NA

# Al ser meses enteros, ya no convertimos a fecha. 
# Solo pasamos el valor o imprimimos "Ninguno"
minimooutliers_mes <- if(!is.na(minimooutliers)) minimooutliers else "Ninguno"
maximooutliers_mes <- if(!is.na(maximooutliers)) maximooutliers else "Ninguno"

print(paste("Mes atípico mínimo:", minimooutliers_mes))
## [1] "Mes atípico mínimo: Ninguno"
print(paste("Mes atípico máximo:", maximooutliers_mes))
## [1] "Mes atípico máximo: Ninguno"

11 Conclusión

El análisis temporal (2010-2016) revela una distribución platicúrtica (curtosis = 1.89) con asimetría negativa leve (-0.21), evidenciando una ocurrencia sostenida de los eventos con una ligera concentración hacia los años más recientes. La alta dispersión (σ≈717 días) respecto a la media central (Oct-2013) y la ausencia estadística de valores atípicos demuestran que los apagados no responden a fallos anómalos puntuales, sino que representan una constante estructural continua en el sistema durante el sexenio evaluado.