1 Estación C02 - Rumihurco

2 1. Carga y preparación de los datos

# ============================================================
# CARGA DE LA BASE DE DATOS
# ============================================================

archivo <- "C:/Users/Usuario/Downloads/C02-Rumihurco_Precipitación-Subhorario_validado.csv"

data0 <- read.csv(
  archivo,
  stringsAsFactors = FALSE
)

# Conversión de fecha
data0$fecha <- as.POSIXct(
  data0$fecha,
  format = "%Y/%m/%d %H:%M:%S"
)

# Revisar periodo disponible
range(data0$fecha, na.rm = TRUE)
## [1] "2019-01-01 00:00:00 -05" "2025-12-31 23:55:00 -05"

3 2. Serie temporal

La serie temporal corresponde a una sucesión de observaciones registradas a lo largo del tiempo. Se analiza inicialmente la serie original de precipitación con resolución de 5 minutos.

# ============================================================
# SERIE TEMPORAL ORIGINAL DE 5 MINUTOS
# MEDIA Y TENDENCIA
# ============================================================

serie_temporal <- data0[
  !is.na(data0$valor),
]

# Media de toda la serie
media_precipitacion <- mean(
  serie_temporal$valor,
  na.rm = TRUE
)

plot_5min <- ggplot(
  data = serie_temporal,
  aes(
    x = fecha,
    y = valor
  )
) +
  
  # Datos observados
  geom_line(
    color = "grey60",
    linewidth = 0.25
  ) +
  
  # Media
  geom_hline(
    yintercept = media_precipitacion,
    color = "blue",
    linetype = "dashed",
    linewidth = 0.7
  ) +
  
  # Tendencia lineal
  geom_smooth(
    method = "lm",
    formula = y ~ x,
    se = FALSE,
    color = "red",
    linewidth = 0.8
  ) +
  
  labs(
    title = "Serie temporal de precipitación - Estación C02 Rumihurco",
    subtitle = "Resolución temporal: 5 minutos",
    x = "Periodo de tiempo",
    y = "Precipitación [mm]",
    caption = "Elaborado por: Arelys Quimbita"
  ) +
  
  theme_bw() +
  
  theme(
    plot.title = element_text(
      hjust = 0.5,
      face = "bold"
    ),
    plot.subtitle = element_text(
      hjust = 0.5
    ),
    plot.caption = element_text(
      hjust = 1
    )
  )

plot_5min

Interpretación: La serie temporal presenta una elevada variabilidad asociada con la ocurrencia intermitente de eventos de precipitación. La línea azul representa el valor medio de la serie, mientras que la línea roja permite realizar una evaluación visual preliminar de la tendencia temporal. Los vacíos de información deben diferenciarse de cambios reales en el comportamiento de la precipitación.

4 3. Agregación temporal

Se obtienen series acumuladas para duraciones de 15, 30, 120 y 1440 minutos a partir de la serie original de 5 minutos.

# ============================================================
# AGREGACIÓN TEMPORAL
# ============================================================

# Serie original de 5 minutos
zdata5min <- zoo(
  data0$valor,
  data0$fecha
)

# ------------------------------------------------------------
# Función que suma únicamente cuando el intervalo está completo
# ------------------------------------------------------------

suma_completa <- function(x, n_esperado) {
  
  if (
    length(x) == n_esperado &&
    !any(is.na(x))
  ) {
    sum(x)
  } else {
    NA_real_
  }
}


# 15 minutos = 3 datos de 5 minutos
zdata15min <- aggregate(
  zdata5min,
  cut(index(zdata5min), "15 min"),
  function(x) suma_completa(x, 3)
)


# 30 minutos = 6 datos de 5 minutos
zdata30min <- aggregate(
  zdata5min,
  cut(index(zdata5min), "30 min"),
  function(x) suma_completa(x, 6)
)



# 120 minutos = 24 datos de 5 minutos
zdata120min <- aggregate(
  zdata5min,
  cut(index(zdata5min), "2 hours"),
  function(x) suma_completa(x, 24)
)


# 1440 minutos = 1 día = 288 datos de 5 minutos
zdata1440min <- aggregate(
  zdata5min,
  as.Date(index(zdata5min)),
  function(x) suma_completa(x, 288)
)

5 4. Series de precipitación para todas las duraciones

# ============================================================
# CONVERTIR LAS SERIES ZOO A DATA.FRAME
# ============================================================

data5 <- data.frame(
  fecha = as.POSIXct(index(zdata5min)),
  precipitacion = as.numeric(zdata5min),
  duracion = "5 min"
)

data15 <- data.frame(
  fecha = as.POSIXct(index(zdata15min)),
  precipitacion = as.numeric(zdata15min),
  duracion = "15 min"
)

data30 <- data.frame(
  fecha = as.POSIXct(index(zdata30min)),
  precipitacion = as.numeric(zdata30min),
  duracion = "30 min"
)

data120 <- data.frame(
  fecha = as.POSIXct(index(zdata120min)),
  precipitacion = as.numeric(zdata120min),
  duracion = "120 min"
)

data1440 <- data.frame(
  fecha = as.POSIXct(index(zdata1440min)),
  precipitacion = as.numeric(zdata1440min),
  duracion = "1440 min"
)


# Unir todas las duraciones
series_total <- rbind(
  data5,
  data15,
  data30,
  data120,
  data1440
)


# Orden lógico de las duraciones
series_total$duracion <- factor(
  series_total$duracion,
  levels = c(
    "5 min",
    "15 min",
    "30 min",
    "120 min",
    "1440 min"
  )
)
# ============================================================
# SERIES PARA TODAS LAS DURACIONES
# ============================================================

plot_series <- ggplot(
  data = series_total,
  aes(
    x = fecha,
    y = precipitacion
  )
) +
  
  geom_line(
    linewidth = 0.25,
    na.rm = TRUE
  ) +
  
  facet_wrap(
    ~ duracion,
    ncol = 1,
    scales = "free_y"
  ) +
  
  labs(
    title = "Series de precipitación - Estación C02 Rumihurco",
    x = "Fecha",
    y = "Precipitación [mm]",
    caption = "Elaborado por: Arelys Quimbita"
  ) +
  
  theme_bw() +
  
  theme(
    plot.title = element_text(
      hjust = 0.5,
      face = "bold"
    ),
    strip.text = element_text(
      face = "bold"
    ),
    plot.caption = element_text(
      hjust = 1
    )
  )

plot_series

6 5. Escalas temporales: horaria y mensual

Esta sección sigue la comparación de escalas temporales utilizada en clase.

# ============================================================
# ESCALAS TEMPORALES
# SERIE HORARIA Y SERIE MENSUAL
# ============================================================

# ------------------------------------------------------------
# SERIE HORARIA
# 1 hora = 12 intervalos de 5 minutos
# ------------------------------------------------------------

zdata_horaria <- aggregate(
  zdata5min,
  cut(index(zdata5min), "1 hour"),
  function(x) suma_completa(x, 12)
)

data_horaria <- data.frame(
  fecha = as.POSIXct(index(zdata_horaria)),
  precipitacion = as.numeric(zdata_horaria)
)


# ------------------------------------------------------------
# SERIE MENSUAL
# ------------------------------------------------------------

data0$mes <- format(
  data0$fecha,
  "%Y-%m"
)

data_mensual <- aggregate(
  valor ~ mes,
  data = data0,
  FUN = function(x) {
    
    if (all(is.na(x))) {
      NA_real_
    } else {
      sum(x, na.rm = TRUE)
    }
  }
)

data_mensual$fecha <- as.Date(
  paste0(
    data_mensual$mes,
    "-01"
  )
)


# ------------------------------------------------------------
# GRÁFICO HORARIO
# ------------------------------------------------------------

plot_horaria <- ggplot(
  data = data_horaria,
  aes(
    x = fecha,
    y = precipitacion
  )
) +
  
  geom_line(
    linewidth = 0.25
  ) +
  
  labs(
    title = "Serie temporal horaria",
    x = "Fecha",
    y = "Precipitación [mm]"
  ) +
  
  theme_bw() +
  
  theme(
    plot.title = element_text(
      hjust = 0.5,
      face = "bold"
    )
  )


# ------------------------------------------------------------
# GRÁFICO MENSUAL
# ------------------------------------------------------------

plot_mensual <- ggplot(
  data = data_mensual,
  aes(
    x = fecha,
    y = valor
  )
) +
  
  geom_line(
    linewidth = 0.6
  ) +
  
  labs(
    title = "Serie temporal mensual",
    x = "Fecha",
    y = "Precipitación acumulada [mm]"
  ) +
  
  theme_bw() +
  
  theme(
    plot.title = element_text(
      hjust = 0.5,
      face = "bold"
    )
  )


# ------------------------------------------------------------
# FIGURA COMBINADA
# ------------------------------------------------------------

figura_escalas <- (
  plot_horaria /
  plot_mensual
) +
  
  plot_annotation(
    title = "Escalas temporales de precipitación - Estación C02 Rumihurco",
    caption = "Elaborado por: Arelys Quimbita"
  )

figura_escalas

Interpretación: La serie horaria conserva con mayor detalle los eventos de corta duración y los picos de precipitación. La agregación mensual suaviza la variabilidad de corto plazo y permite observar el comportamiento acumulado de la precipitación a una escala temporal mayor.

7 6. Estadística descriptiva

De acuerdo con las expresiones utilizadas en clase se calculan parámetros de localización, dispersión y forma.

# ============================================================
# FUNCIÓN DE ESTADÍSTICA DESCRIPTIVA
# ============================================================

estadistica_serie <- function(x) {
  
  # Eliminar NA
  x <- x[!is.na(x)]
  
  # Número de observaciones
  n <- length(x)
  
  # Parámetros de localización
  promedio <- mean(x)
  mediana <- median(x)
  
  # Parámetros de dispersión
  minimo <- min(x)
  maximo <- max(x)
  rango <- maximo - minimo
  
  varianza <- var(x)
  desviacion <- sd(x)
  
  # Coeficiente de variación:
  # Cv = Sx / media
  coef_variacion <- desviacion / promedio
  
  # Coeficiente de asimetría:
  # gx = [1/n sum(xi - media)^3] / Sx^3
  coef_asimetria <- (
    sum((x - promedio)^3) / n
  ) / desviacion^3
  
  # Exceso de curtosis:
  # wx = [1/n sum(xi - media)^4] / Sx^4 - 3
  curtosis <- (
    sum((x - promedio)^4) / n
  ) / desviacion^4 - 3
  
  
  return(
    c(
      Promedio = promedio,
      Mediana = mediana,
      Rango = rango,
      Varianza = varianza,
      Desviacion_estandar = desviacion,
      Coef_variacion = coef_variacion,
      Coef_asimetria = coef_asimetria,
      Curtosis = curtosis
    )
  )
}


# ============================================================
# ESTADÍSTICA PARA CADA DURACIÓN
# ============================================================

est5 <- estadistica_serie(
  as.numeric(zdata5min)
)

est15 <- estadistica_serie(
  as.numeric(zdata15min)
)

est30 <- estadistica_serie(
  as.numeric(zdata30min)
)

est120 <- estadistica_serie(
  as.numeric(zdata120min)
)

est1440 <- estadistica_serie(
  as.numeric(zdata1440min)
)


# ============================================================
# TABLA DE RESULTADOS
# ============================================================

tabla_estadistica <- data.frame(
  
  Duracion = c(
    "5 min",
    "15 min",
    "30 min",
    "120 min",
    "1440 min"
  ),
  
  rbind(
    est5,
    est15,
    est30,
    est120,
    est1440
  )
)


# Redondear
tabla_estadistica[, -1] <- round(
  tabla_estadistica[, -1],
  3
)

tabla_estadistica
##         Duracion Promedio Mediana Rango Varianza Desviacion_estandar
## est5       5 min    0.011     0.0   6.4    0.008               0.090
## est15     15 min    0.033     0.0  12.4    0.059               0.242
## est30     30 min    0.066     0.0  19.5    0.187               0.432
## est120   120 min    0.267     0.0  25.5    1.539               1.241
## est1440 1440 min    3.278     0.1  49.2   45.012               6.709
##         Coef_variacion Coef_asimetria Curtosis
## est5             8.194         18.988  568.695
## est15            7.304         16.180  402.019
## est30            6.511         13.349  271.677
## est120           4.651          7.953   84.189
## est1440          2.047          3.056   10.892

8 7. Diagrama de caja

# ============================================================
# BOXPLOT DE PRECIPITACIÓN POR DURACIÓN
# ============================================================

datos_box <- series_total[
  !is.na(series_total$precipitacion),
]

plot_box <- ggplot(
  data = datos_box,
  aes(
    x = duracion,
    y = precipitacion
  )
) +
  
  geom_boxplot(
    outlier.size = 0.4
  ) +
  
  labs(
    title = "Distribución de la precipitación por duración",
    x = "Duración",
    y = "Precipitación [mm]",
    caption = "Elaborado por: Arelys Quimbita"
  ) +
  
  theme_bw() +
  
  theme(
    plot.title = element_text(
      hjust = 0.5,
      face = "bold"
    ),
    plot.caption = element_text(
      hjust = 1
    )
  )

plot_box

El boxplot permite observar la mediana, los percentiles 25 y 75, los bigotes y los posibles valores atípicos, siguiendo el esquema de estadística descriptiva mostrado en clase.

9 8. Análisis de frecuencia

9.1 8.1 Histogramas para las diferentes duraciones

# ============================================================
# HISTOGRAMAS DE PRECIPITACIÓN
# ============================================================

hist_data <- series_total[
  !is.na(series_total$precipitacion),
]

plot_hist <- ggplot(
  data = hist_data,
  aes(
    x = precipitacion
  )
) +
  
  geom_histogram(
    bins = 20,
    color = "black",
    fill = "grey75"
  ) +
  
  facet_wrap(
    ~ duracion,
    scales = "free",
    ncol = 2
  ) +
  
  labs(
    title = "Histogramas de precipitación - Estación C02 Rumihurco",
    x = "Precipitación [mm]",
    y = "Frecuencia",
    caption = "Elaborado por: Arelys Quimbita"
  ) +
  
  theme_bw() +
  
  theme(
    plot.title = element_text(
      hjust = 0.5,
      face = "bold"
    ),
    strip.text = element_text(
      face = "bold"
    ),
    plot.caption = element_text(
      hjust = 1
    )
  )

plot_hist

9.2 8.2 Frecuencia y densidad: escala horaria y mensual

Esta figura reproduce la lógica utilizada en clase, mostrando frecuencia absoluta y densidad.

# ============================================================
# HISTOGRAMAS HORARIO Y MENSUAL
# FRECUENCIA Y DENSIDAD
# ============================================================

# Eliminar NA
horaria_hist <- data_horaria[
  !is.na(data_horaria$precipitacion),
]

mensual_hist <- data_mensual[
  !is.na(data_mensual$valor),
]


# ------------------------------------------------------------
# Frecuencia horaria
# ------------------------------------------------------------

hist_h_frec <- ggplot(
  horaria_hist,
  aes(x = precipitacion)
) +
  
  geom_histogram(
    bins = 20,
    color = "black",
    fill = "grey75"
  ) +
  
  labs(
    title = "Histograma de precipitación horaria",
    x = "Precipitación [mm]",
    y = "Frecuencia"
  ) +
  
  theme_bw()


# ------------------------------------------------------------
# Densidad horaria
# ------------------------------------------------------------

hist_h_dens <- ggplot(
  horaria_hist,
  aes(
    x = precipitacion,
    y = after_stat(density)
  )
) +
  
  geom_histogram(
    bins = 20,
    color = "black",
    fill = "grey75"
  ) +
  
  labs(
    title = "Histograma de precipitación horaria",
    x = "Precipitación [mm]",
    y = "Densidad"
  ) +
  
  theme_bw()


# ------------------------------------------------------------
# Frecuencia mensual
# ------------------------------------------------------------

hist_m_frec <- ggplot(
  mensual_hist,
  aes(x = valor)
) +
  
  geom_histogram(
    bins = 13,
    color = "black",
    fill = "grey75"
  ) +
  
  labs(
    title = "Histograma de precipitación mensual",
    x = "Precipitación [mm]",
    y = "Frecuencia"
  ) +
  
  theme_bw()


# ------------------------------------------------------------
# Densidad mensual
# ------------------------------------------------------------

hist_m_dens <- ggplot(
  mensual_hist,
  aes(
    x = valor,
    y = after_stat(density)
  )
) +
  
  geom_histogram(
    bins = 13,
    color = "black",
    fill = "grey75"
  ) +
  
  labs(
    title = "Histograma de precipitación mensual",
    x = "Precipitación [mm]",
    y = "Densidad"
  ) +
  
  theme_bw()


# ------------------------------------------------------------
# Figura 2 x 2
# ------------------------------------------------------------

figura_frecuencia <- (
  hist_h_frec | hist_m_frec
) /
(
  hist_h_dens | hist_m_dens
) +
  
  plot_annotation(
    title = "Análisis de frecuencia - Estación C02 Rumihurco",
    caption = "Elaborado por: Arelys Quimbita"
  )

figura_frecuencia

Esto se parece mucho más a la diapositiva de “Frecuencia – H44” de tu ingeniero, donde presenta arriba la frecuencia y abajo la densidad para las escalas horaria y mensual.

10 9. Series máximas anuales

10.1 9.1 Conversión de precipitación a intensidad

# ============================================================
# INTENSIDAD DE PRECIPITACIÓN
# I = P / t
# ============================================================

i5 <- zdata5min / (5 / 60)

i15 <- zdata15min / (15 / 60)

i30 <- zdata30min / (30 / 60)

i120 <- zdata120min / (120 / 60)

i1440 <- zdata1440min / (1440 / 60)

10.2 9.2 Obtención de máximos anuales

# ============================================================
# FUNCIÓN PARA OBTENER EL MÁXIMO DE CADA AÑO
# ============================================================

max_anual <- function(serie) {
  
  fechas <- index(serie)
  
  # Obtener año
  anio <- format(
    as.Date(fechas),
    "%Y"
  )
  
  resultado <- aggregate(
    as.numeric(serie),
    by = list(
      Anio = anio
    ),
    FUN = function(x) {
      
      if (all(is.na(x))) {
        NA_real_
      } else {
        max(
          x,
          na.rm = TRUE
        )
      }
    }
  )
  
  return(resultado)
}


# Máximos para cada duración
max5 <- max_anual(i5)

max15 <- max_anual(i15)

max30 <- max_anual(i30)

max120 <- max_anual(i120)

max1440 <- max_anual(i1440)

10.3 9.3 Tabla de máximos anuales

# ============================================================
# PREPARAR TABLAS
# ============================================================

m5 <- max5
names(m5) <- c(
  "Anio",
  "X5min"
)

m15 <- max15
names(m15) <- c(
  "Anio",
  "X15min"
)

m30 <- max30
names(m30) <- c(
  "Anio",
  "X30min"
)

m120 <- max120
names(m120) <- c(
  "Anio",
  "X120min"
)

m1440 <- max1440
names(m1440) <- c(
  "Anio",
  "X1440min"
)


# Periodo de análisis
m5 <- m5[
  m5$Anio >= "2019" &
  m5$Anio <= "2025",
]

m15 <- m15[
  m15$Anio >= "2019" &
  m15$Anio <= "2025",
]

m30 <- m30[
  m30$Anio >= "2019" &
  m30$Anio <= "2025",
]

m120 <- m120[
  m120$Anio >= "2019" &
  m120$Anio <= "2025",
]

m1440 <- m1440[
  m1440$Anio >= "2019" &
  m1440$Anio <= "2025",
]


# Unir por año
tabla_maximos <- merge(
  m5,
  m15,
  by = "Anio"
)

tabla_maximos <- merge(
  tabla_maximos,
  m30,
  by = "Anio"
)

tabla_maximos <- merge(
  tabla_maximos,
  m120,
  by = "Anio"
)

tabla_maximos <- merge(
  tabla_maximos,
  m1440,
  by = "Anio"
)

tabla_maximos
##   Anio X5min X15min X30min X120min  X1440min
## 1 2019  68.4   44.0   39.0    9.80 1.6250000
## 2 2020  57.6   28.0   21.8    9.85 0.5541667
## 3 2021  58.8   49.6   33.6   12.70 2.0500000
## 4 2022  49.2   43.6   30.4    8.55 1.3750000
## 5 2023  62.4   45.6   27.6   11.00 1.6750000
## 6 2024  43.2   29.6   22.8    8.00 1.9041667
## 7 2025  76.8   46.4   31.8   12.75 1.8166667

10.4 9.4 Máximos anuales y tendencia

# ============================================================
# PASAR TABLA A FORMATO LARGO
# ============================================================

maximos_largos <- melt(
  tabla_maximos,
  id.vars = "Anio",
  variable.name = "Duracion",
  value.name = "Intensidad"
)


# Etiquetas
maximos_largos$Duracion <- factor(
  maximos_largos$Duracion,
  levels = c(
    "X5min",
    "X15min",
    "X30min",
    "X120min",
    "X1440min"
  ),
  labels = c(
    "5 min",
    "15 min",
    "30 min",
    "120 min",
    "1440 min"
  )
)


# Año numérico
maximos_largos$Anio <- as.numeric(
  as.character(
    maximos_largos$Anio
  )
)


# ============================================================
# GRÁFICO
# ============================================================

plot_maximos <- ggplot(
  data = maximos_largos,
  aes(
    x = Anio,
    y = Intensidad
  )
) +
  
  geom_point(
    size = 2
  ) +
  
  geom_smooth(
    method = "lm",
    formula = y ~ x,
    se = FALSE,
    linetype = "dashed",
    linewidth = 0.8
  ) +
  
  facet_wrap(
    ~ Duracion,
    scales = "free_y",
    ncol = 2
  ) +
  
  scale_x_continuous(
    breaks = 2019:2025
  ) +
  
  labs(
    title = "Máximas anuales de intensidad - Estación C02 Rumihurco",
    subtitle = "Análisis de tendencia por duración",
    x = "Año",
    y = "Intensidad máxima anual [mm/h]",
    caption = "Elaborado por: Arelys Quimbita"
  ) +
  
  theme_bw() +
  
  theme(
    plot.title = element_text(
      hjust = 0.5,
      face = "bold"
    ),
    plot.subtitle = element_text(
      hjust = 0.5
    ),
    strip.text = element_text(
      face = "bold"
    ),
    plot.caption = element_text(
      hjust = 1
    )
  )

plot_maximos

Interpretación de tendencia: Las series de máximas anuales presentan comportamientos diferentes según la duración. Debido a que el periodo disponible comprende únicamente siete años, las líneas ajustadas deben considerarse como una evaluación visual preliminar y no como evidencia estadística concluyente de estacionaridad o no estacionaridad.

11 10. Histogramas de máximas anuales

# ============================================================
# HISTOGRAMAS DE MÁXIMAS ANUALES
# ============================================================

plot_hist_max <- ggplot(
  data = maximos_largos,
  aes(
    x = Intensidad
  )
) +
  
  geom_histogram(
    bins = 4,
    color = "black",
    fill = "grey75"
  ) +
  
  facet_wrap(
    ~ Duracion,
    scales = "free_x",
    ncol = 2
  ) +
  
  labs(
    title = "Histogramas de máximas anuales de intensidad",
    subtitle = "Estación C02 - Rumihurco",
    x = "Intensidad máxima anual [mm/h]",
    y = "Frecuencia",
    caption = "Elaborado por: Arelys Quimbita"
  ) +
  
  theme_bw() +
  
  theme(
    plot.title = element_text(
      hjust = 0.5,
      face = "bold"
    ),
    plot.subtitle = element_text(
      hjust = 0.5
    ),
    strip.text = element_text(
      face = "bold"
    ),
    plot.caption = element_text(
      hjust = 1
    )
  )

plot_hist_max

12 11. Comentario general

Las series muestran que la agregación temporal influye directamente en la magnitud y variabilidad de la precipitación. Las duraciones cortas presentan una alta concentración de valores bajos y eventos intensos aislados, produciendo distribuciones fuertemente asimétricas.

Al aumentar la duración, aumenta la precipitación acumulada y la dispersión absoluta. Sin embargo, disminuyen la asimetría y el coeficiente de variación, indicando una reducción de la variabilidad relativa.

Las intensidades máximas anuales presentan un comportamiento inverso: las mayores intensidades corresponden a las duraciones cortas, mientras que la intensidad disminuye conforme aumenta la duración del intervalo de acumulación.

El análisis de tendencias de máximos anuales permite identificar posibles cambios temporales; sin embargo, debido a la longitud limitada del registro entre 2019 y 2025, estas tendencias deben interpretarse con cautela.