1 Objetivo del análisis

Este documento transforma los datos mensuales del archivo Excel en una serie de tiempo con frecuencia mensual, iniciando en enero de 1988. Además, genera gráficos exploratorios, gráficos de tendencia, análisis por estación climática, análisis por mes específico, descomposición de la serie, autocorrelación y anomalías mensuales. Todos los gráficos se muestran dentro del documento y también se guardan automáticamente en una carpeta local para su posterior uso en informes, artículos o publicaciones en RPubs.

2 1. Configuración inicial

En este bloque se definen las opciones generales del documento, se cargan los paquetes necesarios y se crea una función para guardar los gráficos en alta resolución.

knitr::opts_chunk$set(
  echo = TRUE,
  message = FALSE,
  warning = FALSE,
  fig.width = 11,
  fig.height = 6,
  dpi = 300,
  out.width = "100%"
)

# Paquetes requeridos
paquetes <- c(
  "readxl", "dplyr", "tidyr", "lubridate", "ggplot2",
  "forecast", "zoo", "scales", "stringr", "knitr"
)

paquetes_faltantes <- paquetes[!paquetes %in% rownames(installed.packages())]
if (length(paquetes_faltantes) > 0) {
  install.packages(paquetes_faltantes, dependencies = TRUE)
}

invisible(lapply(paquetes, library, character.only = TRUE))
## 
## 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
## 
## Adjuntando el paquete: 'lubridate'
## The following objects are masked from 'package:base':
## 
##     date, intersect, setdiff, union
## Warning: package 'forecast' was built under R version 4.5.3
## 
## Adjuntando el paquete: 'zoo'
## The following objects are masked from 'package:base':
## 
##     as.Date, as.Date.numeric
# Carpeta para guardar los gráficos generados
carpeta_graficos <- "graficos_series_tiempo"
if (!dir.exists(carpeta_graficos)) dir.create(carpeta_graficos)

# Función para guardar gráficos con calidad publicable
guardar_grafico <- function(grafico, nombre, ancho = 12, alto = 7, dpi = 300) {
  ggplot2::ggsave(
    filename = file.path(carpeta_graficos, nombre),
    plot = grafico,
    width = ancho,
    height = alto,
    dpi = dpi,
    bg = "white"
  )
}

# Paleta institucional sugerida
color_principal <- "#005B96"
color_secundario <- "#F2A900"
color_terciario <- "#2E7D32"
color_alerta <- "#C62828"
color_gris <- "#4D4D4D"

3 2. Lectura del archivo Excel

Este bloque lee el archivo Excel desde la ruta indicada. En Windows se recomienda usar / en lugar de \. Si el archivo no se encuentra en la ruta definida, R abrirá una ventana para seleccionarlo manualmente.

ruta_archivo <- "C:/Users/USUARIO/Documents/CAMBIO CLIMATICO/datos_precipitación.xlsx"

if (!file.exists(ruta_archivo)) {
  message("No se encontró el archivo en la ruta indicada. Seleccione el archivo manualmente.")
  ruta_archivo <- file.choose()
}

datos_raw <- readxl::read_excel(ruta_archivo, sheet = "Hoja1")

# Revisión rápida de la estructura original
str(datos_raw)
## tibble [474 × 1] (S3: tbl_df/tbl/data.frame)
##  $ Precipitación: chr [1:474] "39.1" "33.1" "90.5" "53.1" ...
head(datos_raw)

4 3. Preparación de la base mensual

El archivo contiene una columna de datos mensuales. En este bloque se crea una fecha mensual desde enero de 1988, se identifican año, mes, nombre del mes y estación climática. Para la estación lluviosa se considera diciembre a mayo; para la estación seca, junio a noviembre.

meses_esp <- c(
  "Enero", "Febrero", "Marzo", "Abril", "Mayo", "Junio",
  "Julio", "Agosto", "Septiembre", "Octubre", "Noviembre", "Diciembre"
)

serie_df <- datos_raw %>%
  dplyr::rename(valor = 1) %>%
  dplyr::mutate(valor = as.numeric(valor)) %>%
  dplyr::filter(!is.na(valor)) %>%
  dplyr::mutate(
    fecha = seq.Date(from = as.Date("1988-01-01"), by = "month", length.out = dplyr::n()),
    anio = lubridate::year(fecha),
    mes = lubridate::month(fecha),
    mes_nombre = factor(meses_esp[mes], levels = meses_esp),
    estacion = dplyr::case_when(
      mes %in% c(12, 1, 2, 3, 4, 5) ~ "Lluviosa (dic-may)",
      mes %in% c(6, 7, 8, 9, 10, 11) ~ "Seca (jun-nov)",
      TRUE ~ NA_character_
    ),
    # Diciembre se asigna al año climático siguiente para analizar la estación lluviosa completa.
    anio_estacion = dplyr::if_else(mes == 12, anio + 1L, anio)
  )

knitr::kable(head(serie_df, 12), caption = "Primeros 12 registros de la base procesada")
Primeros 12 registros de la base procesada
valor fecha anio mes mes_nombre estacion anio_estacion
39.1 1988-01-01 1988 1 Enero Lluviosa (dic-may) 1988
33.1 1988-02-01 1988 2 Febrero Lluviosa (dic-may) 1988
90.5 1988-03-01 1988 3 Marzo Lluviosa (dic-may) 1988
53.1 1988-04-01 1988 4 Abril Lluviosa (dic-may) 1988
13.4 1988-05-01 1988 5 Mayo Lluviosa (dic-may) 1988
2.3 1988-06-01 1988 6 Junio Seca (jun-nov) 1988
0.0 1988-07-01 1988 7 Julio Seca (jun-nov) 1988
0.0 1988-08-01 1988 8 Agosto Seca (jun-nov) 1988
0.0 1988-09-01 1988 9 Septiembre Seca (jun-nov) 1988
0.3 1988-10-01 1988 10 Octubre Seca (jun-nov) 1988
0.0 1988-11-01 1988 11 Noviembre Seca (jun-nov) 1988
1.0 1988-12-01 1988 12 Diciembre Lluviosa (dic-may) 1989
knitr::kable(tail(serie_df, 12), caption = "Últimos 12 registros de la base procesada")
Últimos 12 registros de la base procesada
valor fecha anio mes mes_nombre estacion anio_estacion
0.0 2026-07-01 2026 7 Julio Seca (jun-nov) 2026
0.2 2026-08-01 2026 8 Agosto Seca (jun-nov) 2026
0.0 2026-09-01 2026 9 Septiembre Seca (jun-nov) 2026
1.0 2026-10-01 2026 10 Octubre Seca (jun-nov) 2026
34.0 2026-11-01 2026 11 Noviembre Seca (jun-nov) 2026
72.2 2026-12-01 2026 12 Diciembre Lluviosa (dic-may) 2027
177.3 2027-01-01 2027 1 Enero Lluviosa (dic-may) 2027
176.2 2027-02-01 2027 2 Febrero Lluviosa (dic-may) 2027
30.4 2027-03-01 2027 3 Marzo Lluviosa (dic-may) 2027
22.4 2027-04-01 2027 4 Abril Lluviosa (dic-may) 2027
5.9 2027-05-01 2027 5 Mayo Lluviosa (dic-may) 2027
5.1 2027-06-01 2027 6 Junio Seca (jun-nov) 2027

5 4. Conversión a serie de tiempo mensual

Aquí se convierte la columna numérica en un objeto ts de R, con frecuencia 12 porque los datos son mensuales.

serie_ts <- ts(serie_df$valor, start = c(1988, 1), frequency = 12)

serie_ts
##        Jan   Feb   Mar   Apr   May   Jun   Jul   Aug   Sep   Oct   Nov   Dec
## 1988  39.1  33.1  90.5  53.1  13.4   2.3   0.0   0.0   0.0   0.3   0.0   1.0
## 1989  49.8  95.6  39.0  17.9   0.0   0.0   0.0   0.2   0.1   2.3   0.1   8.4
## 1990  20.0   7.3  28.9   6.5   9.7   2.6   0.0   0.0   1.1  35.2  98.3 116.7
## 1991 271.3 125.0 205.0 254.7 271.5 338.9 231.6  23.4  46.8   1.7   0.7  25.6
## 1992   1.7 202.6  31.6   0.4   2.9   0.6   0.0   0.0   0.1   8.5 115.1 106.0
## 1993  40.3  78.0  95.9  35.1  42.6   1.6   0.0   0.0   0.0   0.3   0.0  34.0
## 1994 277.6  44.2  75.7  79.6   0.6   0.0   0.7   0.0   0.0   3.5   0.0   3.8
## 1995  70.6 333.3 138.3  95.7  23.3   0.0   0.8  16.5   1.5   0.1   2.4   2.8
## 1996   0.0  96.9  30.0  44.2  23.8   0.0   1.0   0.2  12.2   0.0   0.6   5.0
## 1997 232.3 164.0 189.1  60.5   1.4   1.0   0.1   0.0   6.1   0.9   0.0   0.5
## 1998  32.2  76.3  59.3  37.8   1.2   1.7   0.0   0.0   0.0   0.0   0.1   8.8
## 1999  57.2  95.9  28.4  36.2  17.0   0.1   0.0   0.2   1.9   0.0   3.2  18.8
## 2000 106.6 139.3 300.0 234.8 145.8   9.4   0.5   0.0   0.0   0.0   0.2   8.8
## 2001  30.6 181.9  93.9  57.0   0.1   6.0   0.0   0.0   0.1   0.4   1.8   1.7
## 2002  72.6  56.8 183.2  27.5  73.6   0.7   0.0   0.0   0.4   2.5   0.4  75.0
## 2003 139.5 153.2  34.5  57.3   7.9   8.6   1.2   3.0   0.0   0.1   0.1   8.8
## 2004  46.8  91.2 197.7  62.0   0.1   0.0   0.8   0.0   0.0   0.0   0.6   0.3
## 2005  71.9 128.4 217.9  79.1  54.8 110.7  50.0  65.0  68.5  55.1 157.4 292.1
## 2006 298.9 357.6 460.2 245.1 216.9  81.9  20.6   0.2   0.2   0.0  17.4   0.0
## 2007  29.6 322.7 122.1 135.7  19.0   1.8   0.2   2.3   0.1   0.5   1.5  11.9
## 2008  89.7  76.3  38.8  62.1  54.2   5.4   0.1   0.2   0.5   0.0   1.8  18.3
## 2009   0.0   2.1   2.5 122.0 242.9 301.9  84.4  10.0   0.2   0.2   0.0   0.0
## 2010  60.9 233.7 230.1 132.3  18.4   0.9   0.0   0.2   0.0   1.5   0.7  31.7
## 2011  59.3 181.5  25.4  24.5   9.1   0.2   0.1   0.0   0.0   0.1   1.3  26.1
## 2012  24.1 131.6 153.4  23.3  14.6   7.3   0.0   1.7   1.4   0.0   0.4   0.0
## 2013   0.0   0.0   0.0   0.0  22.3  64.1 153.7 118.0 269.0   0.0   0.5   0.1
## 2014   0.0   2.9   0.0   5.6   1.2   0.0  60.7 157.9 161.9  16.9   0.3   1.1
## 2015  99.3  26.6 121.8 108.7   6.9   2.7   2.8   0.0   1.5   0.2  21.3 222.9
## 2016 236.4 151.7  49.1   5.5   2.2   4.6   0.5   0.6   1.4   0.8   0.2  22.5
## 2017  28.2   0.0  11.6   0.0   0.0   0.0   3.2   0.7  80.7  98.1  92.5 126.5
## 2018 185.9  79.9  78.2 115.3   3.3   3.9   0.1   0.6   0.0   3.1 149.1   1.3
## 2019   0.0  30.0  63.1 122.4  20.3  69.4   0.3  42.5   4.5   0.0   0.1 212.4
## 2020 295.7 235.4  41.6  58.0  11.1   0.0   0.0   0.0   0.0   2.3  22.4   0.4
## 2021   0.0 131.5 102.5 245.7 158.3  13.3   0.3  10.0   0.0   1.3   0.3   0.0
## 2022   0.1   7.4  62.2  76.2  47.7   0.3   0.0  28.6  50.3  10.4   1.5   8.3
## 2023   0.2   0.5   5.1  19.8  28.9 115.9 195.1  96.1  29.5  21.6   7.3 124.9
## 2024 131.4  81.6  94.9   6.5   4.5   0.8   0.0   0.9   0.0   0.0   2.3  96.3
## 2025 278.7 150.7 121.6  82.5   7.4   0.2   1.8   0.0   8.5   0.4  20.1  22.3
## 2026 194.7  48.1  59.7  16.9   0.0   0.1   0.0   0.2   0.0   1.0  34.0  72.2
## 2027 177.3 176.2  30.4  22.4   5.9   5.1
summary(serie_ts)
##    Min. 1st Qu.  Median    Mean 3rd Qu.    Max. 
##    0.00    0.20    7.30   47.88   67.62  460.20

6 5. Gráfico general de la serie mensual

Este gráfico permite observar la evolución completa de la variable en el tiempo, incluyendo valores altos, valores bajos, cambios de régimen y posibles eventos extremos.

p_serie_general <- ggplot(serie_df, aes(x = fecha, y = valor)) +
  geom_line(color = color_principal, linewidth = 0.55) +
  geom_smooth(method = "loess", se = FALSE, color = color_alerta, linewidth = 0.9) +
  labs(
    title = "Serie mensual completa",
    subtitle = "Línea azul: datos mensuales; línea roja: tendencia suavizada",
    x = "Fecha",
    y = "Valor observado"
  ) +
  scale_x_date(date_breaks = "3 years", date_labels = "%Y") +
  theme_minimal(base_size = 14) +
  theme(axis.text.x = element_text(angle = 45, hjust = 1))

p_serie_general

guardar_grafico(p_serie_general, "01_serie_mensual_completa.png")

7 6. Tendencia anual de la serie

Este bloque resume la serie por año y calcula la tendencia anual. Es útil cuando se desea reducir la variabilidad mensual y observar cambios de mediano o largo plazo.

serie_anual <- serie_df %>%
  dplyr::group_by(anio) %>%
  dplyr::summarise(
    promedio_anual = mean(valor, na.rm = TRUE),
    acumulado_anual = sum(valor, na.rm = TRUE),
    maximo_anual = max(valor, na.rm = TRUE),
    minimo_anual = min(valor, na.rm = TRUE),
    .groups = "drop"
  )

p_tendencia_anual <- ggplot(serie_anual, aes(x = anio, y = promedio_anual)) +
  geom_line(color = color_gris, linewidth = 0.6) +
  geom_point(color = color_principal, size = 2) +
  geom_smooth(method = "lm", se = TRUE, color = color_alerta, fill = "#FADBD8", linewidth = 1) +
  labs(
    title = "Tendencia anual del promedio mensual",
    subtitle = "La línea roja representa la tendencia lineal estimada",
    x = "Año",
    y = "Promedio anual"
  ) +
  theme_minimal(base_size = 14)

p_tendencia_anual

guardar_grafico(p_tendencia_anual, "02_tendencia_anual_promedio.png")

modelo_tendencia_anual <- lm(promedio_anual ~ anio, data = serie_anual)
summary(modelo_tendencia_anual)
## 
## Call:
## lm(formula = promedio_anual ~ anio, data = serie_anual)
## 
## Residuals:
##     Min      1Q  Median      3Q     Max 
## -29.200 -18.891  -7.031   6.537 103.148 
## 
## Coefficients:
##               Estimate Std. Error t value Pr(>|t|)
## (Intercept) -148.17216  820.15432  -0.181    0.858
## anio           0.09779    0.40854   0.239    0.812
## 
## Residual standard error: 29.83 on 38 degrees of freedom
## Multiple R-squared:  0.001506,   Adjusted R-squared:  -0.02477 
## F-statistic: 0.0573 on 1 and 38 DF,  p-value: 0.8121

#La Figura muestra la variación anual del promedio mensual de precipitación registrada en la estación meteorológica de Portoviejo durante el período de estudio. Se observa una marcada variabilidad interanual, con valores que oscilan aproximadamente entre 18 y 135 mm. Los mayores promedios se registran alrededor de 1991 y 2006, mientras que los valores más bajos se presentan a finales de la década de 1980 y en algunos años de la década de 1990. A partir de 2010, la serie muestra un comportamiento más estable, con valores entre 35 y 60 mm, aunque persisten fluctuaciones. La línea de tendencia presenta una ligera pendiente positiva, pero poco significativa frente a la variabilidad de los datos, lo que indica que el comportamiento está dominado principalmente por las variaciones entre años.

8 7. Promedio mensual climatológico

Este gráfico muestra el comportamiento promedio de cada mes considerando todos los años disponibles. Es útil para identificar la estacionalidad intraanual.

promedio_mensual <- serie_df %>%
  dplyr::group_by(mes, mes_nombre) %>%
  dplyr::summarise(
    promedio = mean(valor, na.rm = TRUE),
    mediana = median(valor, na.rm = TRUE),
    desviacion = sd(valor, na.rm = TRUE),
    .groups = "drop"
  )

p_promedio_mensual <- ggplot(promedio_mensual, aes(x = mes_nombre, y = promedio, group = 1)) +
  geom_col(fill = color_principal, alpha = 0.82) +
  geom_line(color = color_secundario, linewidth = 1.2) +
  geom_point(color = color_alerta, size = 3) +
  labs(
    title = "Promedio mensual histórico",
    subtitle = "Promedio de cada mes calculado para todo el periodo disponible",
    x = "Mes",
    y = "Promedio mensual"
  ) +
  theme_minimal(base_size = 14) +
  theme(axis.text.x = element_text(angle = 45, hjust = 1))

p_promedio_mensual

guardar_grafico(p_promedio_mensual, "03_promedio_mensual_historico.png")

knitr::kable(promedio_mensual, digits = 2, caption = "Estadísticos mensuales históricos")
Estadísticos mensuales históricos
mes mes_nombre promedio mediana desviacion
1 Enero 93.76 58.25 97.61
2 Febrero 113.28 95.75 93.01
3 Marzo 97.83 69.40 93.80
4 Abril 71.75 57.15 70.41
5 Mayo 39.62 12.25 68.60
6 Junio 29.10 1.75 74.07
7 Julio 20.78 0.20 54.35
8 Agosto 14.85 0.20 35.31
9 Septiembre 19.19 0.20 51.63
10 Octubre 6.91 0.40 18.51
11 Noviembre 19.38 0.70 41.90
12 Diciembre 44.03 8.80 70.12

9 8. Distribución mensual mediante boxplot

El boxplot permite comparar la variabilidad de cada mes. Es especialmente útil para detectar meses con mayor dispersión o valores extremos.

p_boxplot_mensual <- ggplot(serie_df, aes(x = mes_nombre, y = valor, fill = mes_nombre)) +
  geom_boxplot(alpha = 0.85, outlier.color = color_alerta, outlier.size = 2) +
  labs(
    title = "Distribución de valores por mes",
    subtitle = "Comparación de variabilidad mensual en todo el periodo analizado",
    x = "Mes",
    y = "Valor observado"
  ) +
  theme_minimal(base_size = 14) +
  theme(
    axis.text.x = element_text(angle = 45, hjust = 1),
    legend.position = "none"
  )

p_boxplot_mensual

guardar_grafico(p_boxplot_mensual, "04_boxplot_mensual.png")

10 9. Mapa de calor año-mes

El mapa de calor permite observar patrones temporales combinando años y meses. Es útil para identificar periodos húmedos, secos, anomalías o valores extremos.

p_heatmap <- ggplot(serie_df, aes(x = mes_nombre, y = factor(anio), fill = valor)) +
  geom_tile(color = "white", linewidth = 0.15) +
  scale_fill_gradientn(
    colours = c("#F7FBFF", "#6BAED6", "#2171B5", "#08306B"),
    name = "Valor"
  ) +
  labs(
    title = "Mapa de calor mensual por año",
    subtitle = "Cada celda representa el valor mensual observado",
    x = "Mes",
    y = "Año"
  ) +
  theme_minimal(base_size = 13) +
  theme(axis.text.x = element_text(angle = 45, hjust = 1))

p_heatmap

guardar_grafico(p_heatmap, "05_mapa_calor_anio_mes.png", ancho = 12, alto = 10)

11 10. Análisis por estación climática

En este bloque se separa la serie en estación lluviosa y estación seca. Para la estación lluviosa se considera diciembre a mayo; por ello, diciembre se asigna al año climático siguiente.

resumen_estacional <- serie_df %>%
  dplyr::group_by(estacion, anio_estacion) %>%
  dplyr::summarise(
    promedio_estacional = mean(valor, na.rm = TRUE),
    acumulado_estacional = sum(valor, na.rm = TRUE),
    maximo_estacional = max(valor, na.rm = TRUE),
    minimo_estacional = min(valor, na.rm = TRUE),
    n_meses = dplyr::n(),
    .groups = "drop"
  ) %>%
  dplyr::filter(n_meses == 6)

knitr::kable(head(resumen_estacional, 12), digits = 2, caption = "Resumen por estación climática")
Resumen por estación climática
estacion anio_estacion promedio_estacional acumulado_estacional maximo_estacional minimo_estacional n_meses
Lluviosa (dic-may) 1989 33.88 203.3 95.6 0.0 6
Lluviosa (dic-may) 1990 13.47 80.8 28.9 6.5 6
Lluviosa (dic-may) 1991 207.37 1244.2 271.5 116.7 6
Lluviosa (dic-may) 1992 44.13 264.8 202.6 0.4 6
Lluviosa (dic-may) 1993 66.32 397.9 106.0 35.1 6
Lluviosa (dic-may) 1994 85.28 511.7 277.6 0.6 6
Lluviosa (dic-may) 1995 110.83 665.0 333.3 3.8 6
Lluviosa (dic-may) 1996 32.95 197.7 96.9 0.0 6
Lluviosa (dic-may) 1997 108.72 652.3 232.3 1.4 6
Lluviosa (dic-may) 1998 34.55 207.3 76.3 0.5 6
Lluviosa (dic-may) 1999 40.58 243.5 95.9 8.8 6
Lluviosa (dic-may) 2000 157.55 945.3 300.0 18.8 6

11.1 10.1 Tendencia de la estación lluviosa

Este gráfico presenta la tendencia de la estación lluviosa, definida de diciembre a mayo.

lluviosa <- resumen_estacional %>%
  dplyr::filter(estacion == "Lluviosa (dic-may)")

p_lluviosa <- ggplot(lluviosa, aes(x = anio_estacion, y = promedio_estacional)) +
  geom_line(color = color_gris, linewidth = 0.6) +
  geom_point(color = color_principal, size = 2.2) +
  geom_smooth(method = "lm", se = TRUE, color = color_alerta, fill = "#FADBD8", linewidth = 1) +
  labs(
    title = "Tendencia de la estación lluviosa",
    subtitle = "Estación lluviosa definida como diciembre a mayo",
    x = "Año climático",
    y = "Promedio estacional"
  ) +
  theme_minimal(base_size = 14)

p_lluviosa

guardar_grafico(p_lluviosa, "06_tendencia_estacion_lluviosa.png")

modelo_lluviosa <- lm(promedio_estacional ~ anio_estacion, data = lluviosa)
summary(modelo_lluviosa)
## 
## Call:
## lm(formula = promedio_estacional ~ anio_estacion, data = lluviosa)
## 
## Residuals:
##    Min     1Q Median     3Q    Max 
## -73.77 -39.54 -12.53  27.17 233.59 
## 
## Coefficients:
##                Estimate Std. Error t value Pr(>|t|)
## (Intercept)    782.6683  1688.2228   0.464    0.646
## anio_estacion   -0.3512     0.8407  -0.418    0.679
## 
## Residual standard error: 59.09 on 37 degrees of freedom
## Multiple R-squared:  0.004693,   Adjusted R-squared:  -0.02221 
## F-statistic: 0.1745 on 1 and 37 DF,  p-value: 0.6786

#La Figura muestra la evolución del promedio de precipitación durante la estación lluviosa, comprendida entre diciembre y mayo, en la estación meteorológica de Portoviejo. Se evidencia una alta variabilidad interanual, con valores que oscilan aproximadamente entre 0 y 310 mm, mostrando una diferencia marcada entre años secos y lluviosos. Se destacan eventos de precipitación elevados, como en 1991 con valores superiores a 200 mm y alrededor de 2006 con el máximo cercano a 310 mm, mientras que entre 2012 y 2014 se registran los valores más bajos, cercanos a 0–10 mm. En años posteriores se mantiene la alternancia entre periodos húmedos y secos, con incrementos como en 2016 y 2020, y descensos en 2017, 2022 y 2023 por debajo de 35 mm. La tendencia presenta una ligera pendiente negativa, aunque poco significativa frente a la variabilidad de los datos, lo que indica que el comportamiento está dominado principalmente por la variación interanual de la precipitación. ## 10.2 Tendencia de la estación seca

Este gráfico presenta la tendencia de la estación seca, definida de junio a noviembre.

seca <- resumen_estacional %>%
  dplyr::filter(estacion == "Seca (jun-nov)")

p_seca <- ggplot(seca, aes(x = anio_estacion, y = promedio_estacional)) +
  geom_line(color = color_gris, linewidth = 0.6) +
  geom_point(color = color_terciario, size = 2.2) +
  geom_smooth(method = "lm", se = TRUE, color = color_alerta, fill = "#FADBD8", linewidth = 1) +
  labs(
    title = "Tendencia de la estación seca",
    subtitle = "Estación seca definida como junio a noviembre",
    x = "Año",
    y = "Promedio estacional"
  ) +
  theme_minimal(base_size = 14)

p_seca

guardar_grafico(p_seca, "07_tendencia_estacion_seca.png")

modelo_seca <- lm(promedio_estacional ~ anio_estacion, data = seca)
summary(modelo_seca)
## 
## Call:
## lm(formula = promedio_estacional ~ anio_estacion, data = seca)
## 
## Residuals:
##     Min      1Q  Median      3Q     Max 
## -22.225 -17.432 -14.522   3.319  92.871 
## 
## Coefficients:
##                Estimate Std. Error t value Pr(>|t|)
## (Intercept)   -503.3275   876.3672  -0.574    0.569
## anio_estacion    0.2600     0.4366   0.595    0.555
## 
## Residual standard error: 30.69 on 37 degrees of freedom
## Multiple R-squared:  0.009491,   Adjusted R-squared:  -0.01728 
## F-statistic: 0.3545 on 1 and 37 DF,  p-value: 0.5552

#La Figura muestra la evolución de la precipitación promedio durante la estación seca, comprendida entre junio y noviembre, en la estación meteorológica de Portoviejo durante el período de estudio. Se observa un régimen de precipitaciones generalmente bajas y con alta variabilidad interanual. La mayor parte de los años presenta valores inferiores a 5 mm, lo que confirma que se trata del período más seco del año en la región. Sin embargo, se registran eventos excepcionales como en 1991 con valores superiores a 100 mm, y en 2006, 2009, 2014 y 2023 con acumulados aproximados de 85 mm, 65 mm, 100 mm y 78 mm, respectivamente. Entre estos eventos predominan años con precipitaciones cercanas a cero, evidenciando un contraste marcado entre condiciones normales y años influenciados por eventos climáticos extremos. La tendencia muestra una ligera pendiente positiva, aunque de baja magnitud y condicionada principalmente por los eventos aislados, lo que indica que el comportamiento general de la estación seca sigue siendo predominantemente seco a lo largo del tiempo. ## 10.3 Comparación entre estación lluviosa y seca

Este gráfico permite comparar ambas estaciones climáticas en una misma figura.

p_comparacion_estaciones <- ggplot(resumen_estacional, aes(x = anio_estacion, y = promedio_estacional, color = estacion)) +
  geom_line(linewidth = 0.7) +
  geom_point(size = 2) +
  geom_smooth(method = "lm", se = FALSE, linewidth = 0.9) +
  scale_color_manual(values = c("Lluviosa (dic-may)" = color_principal, "Seca (jun-nov)" = color_terciario)) +
  labs(
    title = "Comparación de tendencias por estación climática",
    subtitle = "Promedio estacional anual para estación lluviosa y estación seca",
    x = "Año climático",
    y = "Promedio estacional",
    color = "Estación"
  ) +
  theme_minimal(base_size = 14)

p_comparacion_estaciones

guardar_grafico(p_comparacion_estaciones, "08_comparacion_tendencias_estacionales.png")

#La Figura muestra la comparación de la precipitación promedio anual entre la estación lluviosa de diciembre a mayo y la estación seca de junio a noviembre en la estación meteorológica de Portoviejo durante el período 1980 a 2026. Se observa que la estación lluviosa presenta los valores más altos de precipitación y una mayor variabilidad entre años, con picos que en algunos casos superan los 300 mm. En contraste, la estación seca mantiene valores mucho más bajos y relativamente estables, generalmente por debajo de 100 mm. Las tendencias en ambas estaciones se mantienen casi constantes a lo largo del período, sin cambios marcados, aunque la estación lluviosa conserva consistentemente los mayores acumulados de precipitación.

11.2 10.4 Tendencia del acumulado por estación climática

Si la variable analizada corresponde a precipitación, el acumulado estacional suele ser más informativo que el promedio, porque representa el volumen total registrado durante la estación lluviosa o seca. Este bloque genera una comparación de acumulados por estación.

p_acumulado_estacional <- ggplot(resumen_estacional, aes(x = anio_estacion, y = acumulado_estacional, color = estacion)) +
  geom_line(linewidth = 0.7) +
  geom_point(size = 2) +
  geom_smooth(method = "lm", se = FALSE, linewidth = 0.9) +
  scale_color_manual(values = c("Lluviosa (dic-may)" = color_principal, "Seca (jun-nov)" = color_terciario)) +
  labs(
    title = "Tendencia del acumulado por estación climática",
    subtitle = "Recomendado cuando la variable corresponde a precipitación u otra magnitud acumulable",
    x = "Año climático",
    y = "Acumulado estacional",
    color = "Estación"
  ) +
  theme_minimal(base_size = 14)

p_acumulado_estacional

guardar_grafico(p_acumulado_estacional, "08b_tendencia_acumulado_estacional.png")

modelo_acumulado_lluviosa <- lm(acumulado_estacional ~ anio_estacion, data = lluviosa)
modelo_acumulado_seca <- lm(acumulado_estacional ~ anio_estacion, data = seca)
summary(modelo_acumulado_lluviosa)
## 
## Call:
## lm(formula = acumulado_estacional ~ anio_estacion, data = lluviosa)
## 
## Residuals:
##     Min      1Q  Median      3Q     Max 
## -442.62 -237.25  -75.16  162.99 1401.52 
## 
## Coefficients:
##                Estimate Std. Error t value Pr(>|t|)
## (Intercept)    4696.010  10129.337   0.464    0.646
## anio_estacion    -2.107      5.044  -0.418    0.679
## 
## Residual standard error: 354.5 on 37 degrees of freedom
## Multiple R-squared:  0.004693,   Adjusted R-squared:  -0.02221 
## F-statistic: 0.1745 on 1 and 37 DF,  p-value: 0.6786
summary(modelo_acumulado_seca)
## 
## Call:
## lm(formula = acumulado_estacional ~ anio_estacion, data = seca)
## 
## Residuals:
##     Min      1Q  Median      3Q     Max 
## -133.35 -104.59  -87.13   19.92  557.23 
## 
## Coefficients:
##               Estimate Std. Error t value Pr(>|t|)
## (Intercept)   -3019.97    5258.20  -0.574    0.569
## anio_estacion     1.56       2.62   0.595    0.555
## 
## Residual standard error: 184.1 on 37 degrees of freedom
## Multiple R-squared:  0.009491,   Adjusted R-squared:  -0.01728 
## F-statistic: 0.3545 on 1 and 37 DF,  p-value: 0.5552

12 11. Tendencia mensual independiente: enero, febrero, marzo y demás meses

Este bloque analiza cada mes por separado. Por ejemplo, enero se compara únicamente contra los eneros de todos los años; febrero contra los febreros de todos los años, y así sucesivamente.

p_tendencia_meses_facetas <- ggplot(serie_df, aes(x = anio, y = valor)) +
  geom_line(color = color_gris, linewidth = 0.45) +
  geom_point(color = color_principal, size = 1.5) +
  geom_smooth(method = "lm", se = TRUE, color = color_alerta, fill = "#FADBD8", linewidth = 0.75) +
  facet_wrap(~ mes_nombre, scales = "free_y", ncol = 3) +
  labs(
    title = "Tendencia independiente por mes",
    subtitle = "Cada panel compara el mismo mes a través de todos los años",
    x = "Año",
    y = "Valor observado"
  ) +
  theme_minimal(base_size = 13)

p_tendencia_meses_facetas

guardar_grafico(p_tendencia_meses_facetas, "09_tendencia_independiente_por_mes_facetas.png", ancho = 14, alto = 10)

#La Figura presenta la tendencia de la precipitación mensual registrada en la estación meteorológica de Portoviejo durante el período 1980–2026. Se observa que enero presenta valores entre 0 y aproximadamente 300 mm, con una ligera tendencia creciente y alta variabilidad interanual. En febrero, los registros oscilan entre 0 y 320 mm, con una distribución dispersa y una tendencia prácticamente estable. Marzo corresponde al mes con los mayores acumulados, alcanzando valores cercanos a 400 mm, aunque con una ligera tendencia decreciente. En abril, las precipitaciones varían entre 0 y 250 mm, con una tendencia casi horizontal y alta dispersión. En mayo, predominan valores inferiores a 50 mm, aunque se presentan eventos aislados de hasta 250 mm, con una leve tendencia a la baja. Entre junio y noviembre predominan precipitaciones muy bajas, generalmente inferiores a 20 mm, aunque se registran eventos extremos como en junio y septiembre con valores cercanos a 300 mm y 250 mm respectivamente. En diciembre, las precipitaciones aumentan nuevamente, con valores entre 0 y 300 mm. En general, las tendencias son poco pronunciadas en todos los meses, lo que indica ausencia de cambios significativos en el comportamiento de la precipitación, predominando la variabilidad interanual. ## 11.1 Generación automática de un gráfico individual por cada mes

Este bloque imprime y guarda un gráfico separado para cada mes. Los archivos se guardan en la carpeta graficos_series_tiempo.

for (m in levels(serie_df$mes_nombre)) {
  datos_mes <- serie_df %>% dplyr::filter(mes_nombre == m)
  
  p_mes <- ggplot(datos_mes, aes(x = anio, y = valor)) +
    geom_line(color = color_gris, linewidth = 0.55) +
    geom_point(color = color_principal, size = 2) +
    geom_smooth(method = "lm", se = TRUE, color = color_alerta, fill = "#FADBD8", linewidth = 0.95) +
    labs(
      title = paste("Tendencia histórica del mes de", m),
      subtitle = paste("Comparación de", m, "en todos los años disponibles"),
      x = "Año",
      y = "Valor observado"
    ) +
    theme_minimal(base_size = 14)
  
  print(p_mes)
  
  nombre_archivo <- paste0("10_tendencia_mes_", stringr::str_to_lower(stringr::str_replace_all(m, " ", "_")), ".png")
  guardar_grafico(p_mes, nombre_archivo, ancho = 10, alto = 5.5)
}

13 12. Gráfico estacional tipo season plot

Este gráfico muestra la forma anual de la serie, comparando los meses dentro de cada año. Es útil para observar si la estacionalidad se mantiene estable o cambia en el tiempo.

p_season <- forecast::ggseasonplot(serie_ts, year.labels = FALSE, continuous = TRUE) +
  labs(
    title = "Gráfico estacional mensual",
    subtitle = "Comparación de la forma intraanual de la serie",
    x = "Mes",
    y = "Valor observado"
  ) +
  theme_minimal(base_size = 14)

p_season

guardar_grafico(p_season, "11_grafico_estacional_seasonplot.png")

14 13. Gráfico de subseries mensuales

El gráfico de subseries permite observar, para cada mes, la media mensual y la variabilidad interna a lo largo del tiempo.

p_subseries <- forecast::ggsubseriesplot(serie_ts) +
  labs(
    title = "Gráfico de subseries mensuales",
    subtitle = "Evolución de cada mes y comparación con su media histórica",
    x = "Mes",
    y = "Valor observado"
  ) +
  theme_minimal(base_size = 14)

p_subseries

guardar_grafico(p_subseries, "12_grafico_subseries_mensuales.png")

15 14. Descomposición clásica de la serie

La descomposición separa la serie en tres componentes: tendencia, estacionalidad y residuo. Se aplica una descomposición aditiva, adecuada cuando la amplitud estacional no depende fuertemente del nivel de la serie.

desc_aditiva <- stats::decompose(serie_ts, type = "additive")

p_desc_aditiva <- forecast::autoplot(desc_aditiva) +
  labs(title = "Descomposición clásica aditiva de la serie") +
  theme_minimal(base_size = 14)

p_desc_aditiva

guardar_grafico(p_desc_aditiva, "13_descomposicion_clasica_aditiva.png", ancho = 12, alto = 8)

16 15. Descomposición STL

La descomposición STL es flexible y suele ser más robusta para series ambientales mensuales porque permite una estimación suavizada de la tendencia y de la estacionalidad.

desc_stl <- stats::stl(serie_ts, s.window = "periodic")

p_desc_stl <- forecast::autoplot(desc_stl) +
  labs(title = "Descomposición STL de la serie mensual") +
  theme_minimal(base_size = 14)

p_desc_stl

guardar_grafico(p_desc_stl, "14_descomposicion_stl.png", ancho = 12, alto = 8)

17 16. Media móvil de 12 meses y 24 meses

Las medias móviles permiten suavizar la serie y visualizar mejor los cambios de mediano plazo. La media móvil de 12 meses reduce el efecto de la estacionalidad anual.

serie_df <- serie_df %>%
  dplyr::mutate(
    media_movil_12 = zoo::rollmean(valor, k = 12, fill = NA, align = "center"),
    media_movil_24 = zoo::rollmean(valor, k = 24, fill = NA, align = "center")
  )

p_medias_moviles <- ggplot(serie_df, aes(x = fecha)) +
  geom_line(aes(y = valor), color = "#B0B0B0", linewidth = 0.35) +
  geom_line(aes(y = media_movil_12), color = color_principal, linewidth = 0.9) +
  geom_line(aes(y = media_movil_24), color = color_alerta, linewidth = 1) +
  labs(
    title = "Serie mensual con medias móviles",
    subtitle = "Gris: serie original; azul: media móvil 12 meses; rojo: media móvil 24 meses",
    x = "Fecha",
    y = "Valor observado"
  ) +
  scale_x_date(date_breaks = "3 years", date_labels = "%Y") +
  theme_minimal(base_size = 14) +
  theme(axis.text.x = element_text(angle = 45, hjust = 1))

p_medias_moviles

guardar_grafico(p_medias_moviles, "15_medias_moviles_12_24_meses.png")

18 17. Anomalías mensuales respecto al promedio histórico del mes

La anomalía se calcula como la diferencia entre el valor observado y el promedio histórico de su respectivo mes. Este análisis permite identificar meses por encima o por debajo del comportamiento esperado.

climatologia_mensual <- serie_df %>%
  dplyr::group_by(mes) %>%
  dplyr::summarise(promedio_mes = mean(valor, na.rm = TRUE), .groups = "drop")

serie_anomalias <- serie_df %>%
  dplyr::left_join(climatologia_mensual, by = "mes") %>%
  dplyr::mutate(
    anomalia = valor - promedio_mes,
    tipo_anomalia = dplyr::if_else(anomalia >= 0, "Positiva", "Negativa")
  )

p_anomalias <- ggplot(serie_anomalias, aes(x = fecha, y = anomalia, fill = tipo_anomalia)) +
  geom_col(width = 25, alpha = 0.9) +
  geom_hline(yintercept = 0, color = "black", linewidth = 0.4) +
  scale_fill_manual(values = c("Positiva" = color_principal, "Negativa" = color_alerta)) +
  labs(
    title = "Anomalías mensuales",
    subtitle = "Diferencia entre el valor observado y el promedio histórico del mismo mes",
    x = "Fecha",
    y = "Anomalía",
    fill = "Tipo"
  ) +
  scale_x_date(date_breaks = "3 years", date_labels = "%Y") +
  theme_minimal(base_size = 14) +
  theme(axis.text.x = element_text(angle = 45, hjust = 1))

p_anomalias

guardar_grafico(p_anomalias, "16_anomalias_mensuales.png", ancho = 13, alto = 6.5)

19 18. Autocorrelación y autocorrelación parcial

La autocorrelación permite evaluar si los valores actuales dependen de valores pasados. En series mensuales ambientales es común observar autocorrelación en rezagos de 12 meses.

p_acf <- forecast::ggAcf(serie_ts, lag.max = 60) +
  labs(
    title = "Función de autocorrelación ACF",
    subtitle = "Rezagos mensuales hasta 60 meses"
  ) +
  theme_minimal(base_size = 14)

p_pacf <- forecast::ggPacf(serie_ts, lag.max = 60) +
  labs(
    title = "Función de autocorrelación parcial PACF",
    subtitle = "Rezagos mensuales hasta 60 meses"
  ) +
  theme_minimal(base_size = 14)

p_acf

guardar_grafico(p_acf, "17_acf_serie_mensual.png")

p_pacf

guardar_grafico(p_pacf, "18_pacf_serie_mensual.png")

20 19. Tabla resumen estadística general

Esta tabla sintetiza la serie mensual y permite reportar los valores principales del periodo analizado.

resumen_general <- serie_df %>%
  dplyr::summarise(
    fecha_inicio = min(fecha),
    fecha_fin = max(fecha),
    n_meses = dplyr::n(),
    promedio = mean(valor, na.rm = TRUE),
    mediana = median(valor, na.rm = TRUE),
    desviacion_estandar = sd(valor, na.rm = TRUE),
    minimo = min(valor, na.rm = TRUE),
    maximo = max(valor, na.rm = TRUE),
    coef_variacion = sd(valor, na.rm = TRUE) / mean(valor, na.rm = TRUE) * 100
  )

knitr::kable(resumen_general, digits = 2, caption = "Resumen estadístico general de la serie mensual")
Resumen estadístico general de la serie mensual
fecha_inicio fecha_fin n_meses promedio mediana desviacion_estandar minimo maximo coef_variacion
1988-01-01 2027-06-01 474 47.88 7.3 76.47 0 460.2 159.72

21 20. Exportación de bases procesadas

Este bloque guarda las bases procesadas en formato CSV para que puedan ser usadas posteriormente en otros análisis.

write.csv(serie_df, file = "serie_mensual_procesada.csv", row.names = FALSE)
write.csv(serie_anual, file = "serie_anual_resumen.csv", row.names = FALSE)
write.csv(resumen_estacional, file = "serie_estacional_resumen.csv", row.names = FALSE)
write.csv(promedio_mensual, file = "promedio_mensual_historico.csv", row.names = FALSE)
write.csv(serie_anomalias, file = "serie_anomalias_mensuales.csv", row.names = FALSE)

22 21. Recomendación de interpretación

Para una interpretación rigurosa, no conviene concluir que existe una tendencia climática solo por observar una pendiente visual. La tendencia debe evaluarse con el modelo lineal, los intervalos de confianza y, si corresponde, con pruebas no paramétricas adicionales. También debe considerarse la calidad de la serie, presencia de datos faltantes, cambios de estación meteorológica, cambios de instrumentos o cambios en el entorno de medición.