En el siguiente ejemplo se utilizan datos diarios de ventas, simulados para presentar algunos ejemplos de con trabajar con series temporales utilizando el tidyverso [datos]. Puntualmente, se muestra como convertir una data en frecuencia diaria a semanal, y como realizar pronósticos con modelos arima usando la data en frecuencia diaria y en frecuencia semanal (vea dplyr como prerrequisito).
library(readxl)
library(tidyverse)
library(tseries)
library(forecast)
data_simulada_venta <- read_excel("data_simulada_venta.xlsx")
data_simulada_venta
# A tibble: 1,356 x 2
fecha ventas
<dttm> <dbl>
1 2016-01-01 00:00:00 0.343
2 2016-01-02 00:00:00 1.28
3 2016-01-04 00:00:00 1.59
4 2016-01-05 00:00:00 1.83
5 2016-01-06 00:00:00 2.29
Convertir la data diaria en datos semanales
El collapse de la data es una operación usada para agregar data, por ejemplo, pasar de una data a nivel de individuos a datos a nivel de viviendas, o en el caso se series temporales pasar de datos de unafrecuencia mayor a una menor, por poner un caso, de mensual a trimestral. En este sentido, una de las operaciones más frecuente es agrupar los datos diarios en semanas, para esto hacemos un by_group por cada semana de los distintos años disponibles en nuestros datos luego de generar dos nuevas variables para identificar los años y las semanas.
a. Creamos las variables (en caso de no estar disponibles) sobre las que deseamos agregar la data. En nuestros casos, usamos el año (anio) y el día de la semana, porque queremos agregar por
semana para cada año.
b. Usamos by_group para agregar la data, combinado con el summarize, que es donde se indica cual es el proceso por el cual se va agregar la data. En este ejemplo, corresponde a la
suma de las ventas diarias. Note que aquí pudiésemos utilizar otras funciones, tales como la media, la varianza o el primer día de la semana, para obtener otra agregación de la data:
data_semanal <- data_simulada_venta %>%
mutate(anio = format(fecha, "%Y"),
dia_semana_num = format(fecha, "%W")) %>%
group_by(anio,dia_semana_num) %>%
summarise(suma_venta = sum(ventas),
fecha = max(fecha))
data_semanal
# A tibble: 229 x 4
# Groups: anio [5]
anio dia_semana_num suma_venta fecha
<chr> <chr> <dbl> <dttm>
1 2016 00 1.62 2016-01-02 00:00:00
2 2016 01 16.6 2016-01-09 00:00:00
3 2016 02 40.9 2016-01-16 00:00:00
4 2016 03 55.8 2016-01-23 00:00:00
5 2016 04 68.3 2016-01-30 00:00:00
6 2016 05 88.9 2016-02-06 00:00:00
7 2016 06 110. 2016-02-13 00:00:00
8 2016 07 120. 2016-02-20 00:00:00
9 2016 08 132. 2016-02-27 00:00:00
10 2016 09 145. 2016-03-05 00:00:00
# ... with 219 more rows
Obtener una data semanal de un solo día de la semana
Otra forma de agregar datos, es obtener una observación (correspondiente a un día en nuestro ejemplo) como representativo de la data agregada (semanal). Aquí, usamos la función wday del paquete lubridate, que nos permite identificar el día de la semana, para posteriormente, obtener un collapse de la data diaria, pero en vez de agregar la data para obtener las semanas (sumamos todos los días para obtener la data semanal), seleccionados uno de los datos semanales. Puntualmente el viernes, pero en caso de otros días de las semanas, solo es necesario modificar el día de la semana seleccionado en el filter.
library(lubridate)
# todos los viernes del primer mes de 2016 o 2017
data_simulada_venta %>%
mutate(anio = format(fecha, "%Y"),
mes = format(fecha, "%B"),
dia_semana_num = format(fecha, "%W"),
dia_semana = wday(fecha)) %>%
filter(dia_semana==5, anio==2016|2017, mes=="enero") %>%
group_by(anio,dia_semana_num) %>%
summarise(suma_venta = sum(ventas),
fecha = max(fecha))
# A tibble: 22 x 4
# Groups: anio [5]
anio dia_semana_num suma_venta fecha
<chr> <chr> <dbl> <dttm>
1 2016 01 2.88 2016-01-07 00:00:00
2 2016 02 7.51 2016-01-14 00:00:00
3 2016 03 9.52 2016-01-21 00:00:00
4 2016 04 11.4 2016-01-28 00:00:00
5 2017 01 150. 2017-01-05 00:00:00
6 2017 02 153. 2017-01-12 00:00:00
7 2017 03 155. 2017-01-19 00:00:00
8 2017 04 158. 2017-01-26 00:00:00
9 2018 01 304. 2018-01-04 00:00:00
10 2018 02 307. 2018-01-11 00:00:00
# ... with 12 more rows
Esta identificación de datos, nos permite también obtener estadísticos y operaciones semanales en función de días de semana específicos. Por ejemplo, podemos obtener la mediana de ventas de los viernes de junio y julio 2016, utilizando la función filter:
data_simulada_venta %>%
mutate(anio = format(fecha, "%Y"),
mes = format(fecha, "%B"),
dia_semana_num = format(fecha, "%W"),
dia_semana = wday(fecha)) %>%
filter(dia_semana==5, anio==2016, mes %in% c("junio", "julio")) %>%
group_by(anio,dia_semana_num) %>%
summarise(suma_venta = median(ventas),
fecha = max(fecha))
`summarise()` regrouping output by 'anio' (override with `.groups` argument)
# A tibble: 9 x 4
# Groups: anio [1]
anio dia_semana_num suma_venta fecha
<chr> <chr> <dbl> <dttm>
1 2016 22 61.0 2016-06-02 00:00:00
2 2016 23 64.3 2016-06-09 00:00:00
3 2016 24 66.4 2016-06-16 00:00:00
4 2016 25 68.7 2016-06-23 00:00:00
5 2016 26 72.9 2016-06-30 00:00:00
6 2016 27 75.5 2016-07-07 00:00:00
7 2016 28 78.9 2016-07-14 00:00:00
8 2016 29 82.7 2016-07-21 00:00:00
9 2016 30 85.9 2016-07-28 00:00:00
Una vez obtenidos los datos semanales, podemos utilizar los paquetes de pronóstico de R (forecast y tseries) para realizar proyecciones sea de las series semanales o diarias:
a. Proyección semanal.
ts(data_semanal$suma_venta) %>%
auto.arima() %>%
forecast(h=5)
Point Forecast Lo 80 Hi 80 Lo 95 Hi 95
230 3369.852 3031.907 3707.797 2853.010 3886.694
231 3755.108 3375.773 4134.443 3174.965 4335.251
232 3727.434 3339.778 4115.089 3134.565 4320.302
233 3685.478 3287.301 4083.655 3076.519 4294.437
234 3653.735 3241.844 4065.626 3023.802 4283.668
b. Proyección diaria (usando los datos de la semana completa).
ts(data_simulada_venta$ventas) %>%
auto.arima() %>%
forecast(h=5)
Point Forecast Lo 80 Hi 80 Lo 95 Hi 95
1357 674.7300 674.3008 675.1591 674.0736 675.3863
1358 675.1442 674.4392 675.8492 674.0659 676.2224
1359 675.5323 674.4952 676.5694 673.9462 677.1184
1360 675.9322 674.4860 677.3784 673.7204 678.1440
1361 676.3322 674.4527 678.2117 673.4578 679.20
c. Proyección diaria (usando solo los lunes para proyectar las ventas de los lunes únicamente).
data_lunes <- data_simulada_venta %>%
mutate(dia_semana_nombre = wday(fecha, label=T),
dia_semana_num = wday(fecha),
anio = format(fecha, "%Y"),
mes = format(fecha, "%B")) %>%
filter(dia_semana_num==2)
auto.arima(data_lunes$ventas) %>%
forecast(h=5)
Point Forecast Lo 80 Hi 80 Lo 95 Hi 95
227 676.2422 675.3601 677.1243 674.8932 677.5913
228 679.2780 678.0324 680.5236 677.3730 681.1829
229 682.2478 680.7087 683.7869 679.8940 684.6016
230 685.3183 683.4556 687.1810 682.4695 688.1671
231 688.3682 686.2326 690.5037 685.1021 691.6342