25 ene 2023

Representar múltiples gráficos (correlogramas) desde una lista en R

En la siguiente entrada se muestra como guardar múltiples gráficos en una lista, para posteriormente representarlos de manera conjunta. Puntualmente, deseamos graficar el correlograma asociado a cada una de las series disponibles en una base de datos, para posteriormente representarlos en un panel conjunto de gráficos. Para ello se utiliza la base EuStockMarkets, una data disponible en el ambiente base de R, siendo una serie de tiempo sobre cotizaciones de diversos índices financieros.
 
library(purrr)
library(tseries)
library(dplyr)
library(ggplot2)
 
EuStockMarkets %>% head()
 
Time Series:
Start = c(1991, 130)
End = c(1991, 135)
Frequency = 260
             DAX    SMI    CAC   FTSE
1991.496 1628.75 1678.1 1772.8 2443.6
1991.500 1613.63 1688.5 1750.5 2460.2
1991.504 1606.51 1678.6 1718.0 2448.2
1991.508 1621.04 1684.1 1708.1 2470.4
1991.512 1618.16 1686.6 1723.1 2484.7
1991.515 1610.61 1671.6 1714.3 2466.8
 
Puntualmente, queremos guardar un correlograma para cada una de las series. Como se tratan de cotizaciones o precios de diversos índices, obtenemos las tasas de crecimiento de cada columna para generar un correlograma de estas tasas de variaciones, lugar de las cotizaciones (recuerde que será muy seguro que las cotizaciones no se comporten como series estacionarias dado que tienen una clara tendencia. En caso de dudas comparar gráficos de la serie en nivel y en variaciones relativas).
 
my_data <- EuStockMarkets %>%
  as.tibble() %>%
  mutate(
    across(everything(),
           ~((./dplyr::lag(.)-1)*100),
           .names= "tc_{.col}"
    )) %>%
  dplyr::select(starts_with("tc_")) %>%
  na.omit()
 
my_data
# A tibble: 1,859 x 4
   tc_DAX tc_SMI  tc_CAC tc_FTSE
    <dbl>  <dbl>   <dbl>   <dbl>
 1 -0.928  0.620 -1.26    0.679
 2 -0.441 -0.586 -1.86   -0.488
 3  0.904  0.328 -0.576   0.907
 4 -0.178  0.148  0.878   0.579
 5 -0.467 -0.889 -0.511  -0.720
 6  1.25   0.676  1.18    0.855
 7  0.578  1.23   1.32    0.824
 8 -0.287 -0.358 -0.193   0.0837
 9  0.637  1.11   0.0171 -0.522
10  0.118  0.437  0.314   1.41 
# ... with 1,849 more rows
 
Una vez tenemos las tasas de variaciones diarias, ahora convertimos cada fila en una serie temporal (map_df); agregamos una columna para representar los rezagos (bacdf$lag); y reorganizaos la base de datos (dplyr::select(lag, everything())). Note la estructura en que queda representada la data. En caso de tener variables no numérica, como fechas o nombres, o dummy representando eventos o temporadas, estas deben omitirse de esta data que servirá de base para generar los gráficos.
 
bacdf <- map_df(my_data, function(ts) acf(ts, plot = FALSE)$acf)
bacdf$lag <- 0:(nrow(bacdf) - 1)
bacdf <- bacdf %>% dplyr::select(lag, everything())
 
bacdf
# A tibble: 33 x 5
     lag        tc_DAX       tc_SMI       tc_CAC       tc_FTSE
   <int>   <dbl[,1,1]>  <dbl[,1,1]>  <dbl[,1,1]>   <dbl[,1,1]>
 1     0  1        ...  1       ...  1       ...  1        ...
 2     1 -0.000771 ...  0.0475  ...  0.0294  ...  0.0924   ...
 3     2 -0.0265   ... -0.0203  ...  0.00330 ... -0.00811  ...
 4     3 -0.0113   ... -0.0178  ... -0.0461  ...  0.00100  ...
 5     4  0.000469 ...  0.00677 ...  0.00565 ... -0.0240   ...
 6     5 -0.0321   ... -0.0459  ... -0.0313  ... -0.0302   ...
 7     6  0.00196  ... -0.0288  ...  0.00812 ... -0.0524   ...
 8     7 -0.0305   ... -0.00663 ... -0.0486  ... -0.0477   ...
 9     8 -0.00909  ...  0.0260  ... -0.0315  ... -0.000642 ...
10     9  0.0229   ...  0.00554 ...  0.0240  ...  0.0278   ...
# ... with 23 more rows
 
Ahora generamos tres argumentos: el nombre de la variable donde tenemos el rezago (lag); el nombre de las variables a representar en mi base de datos y una lista vacía donde guardaremos correlograma asociado a cada serie.
 
myaxis <- colnames(bacdf[1])
mynames <- colnames(bacdf[-1])
graficos <- list()
 
Posteriormente usamos una secuencia for usando la función seq_along(), note que en cada vuelta del bucle va a llamar el nombre de la variable que estamos usando. Ya dentro del bucle se usa ggplot para generar el correlograma, siendo la única diferencia que la variable y se llama como mynames[[i]], de forma tal que este indexado al valor de i, y por tanto se vaya modificando en cada serie. Estos se van guardando en la posición (graficos[[i]]) del mismo nombre de la lista que hemos creado.
 
for (i in seq_along(mynames)) {
  print(i)
 
  g  <-  ggplot(bacdf, aes_string(x = myaxis, y = mynames[[i]])) +
    geom_segment(mapping = aes(xend = lag, yend = 0)) +
    geom_point() +
    geom_hline(yintercept = c(significance_level, -significance_level), lty = 3, color = "blue") +
    ggtitle(mynames[[i]]) +
    theme_minimal() +
    coord_cartesian(xlim = c(2, 35), ylim=c(-.1,0.1))
 
  graficos[[i]] <- ggplotGrob(g)
 
}
 
Finalmente, generamos el gráfico.
 
grid.arrange(grobs=graficos, ncol=2
)


Agradecimientos y créditos: el código base usado dentro del bucle para generar el grafico final se obtuvo de la entrada Plotting multiple ACF with ggplot disponible en stackoverflow.com.

Creando variables por grupos en dplyr (group_by + mutate)

  Simulemos una base de hogares, donde se identifica el hogar, el sexo (1 mujer) y provincia y edad para cada miembro.   # Definir la lista ...