Proyecto final Series de tiempo

Mauricio Martinez Ulloa, Santiago Reyes Castillo, Andrea Santoyo Vega

pkgs

library(tidyverse)
library(fpp3)
library(forecast)
library(prophet)

Datos

Importación

# A tibble: 3,000,888 × 6
      id date       store_nbr family       sales onpromotion
   <dbl> <date>         <dbl> <chr>        <dbl>       <dbl>
 1     0 2013-01-01         1 AUTOMOTIVE       0           0
 2     1 2013-01-01         1 BABY CARE        0           0
 3     2 2013-01-01         1 BEAUTY           0           0
 4     3 2013-01-01         1 BEVERAGES        0           0
 5     4 2013-01-01         1 BOOKS            0           0
 6     5 2013-01-01         1 BREAD/BAKERY     0           0
 7     6 2013-01-01         1 CELEBRATION      0           0
 8     7 2013-01-01         1 CLEANING         0           0
 9     8 2013-01-01         1 DAIRY            0           0
10     9 2013-01-01         1 DELI             0           0
# ℹ 3,000,878 more rows

Convertir a tsibble

train_tsbl <- train |> 
  as_tsibble(index = date, key = c(store_nbr, family)) 

train_tsbl
# A tsibble: 3,000,888 x 6 [1D]
# Key:       store_nbr, family [1,782]
      id date       store_nbr family     sales onpromotion
   <dbl> <date>         <dbl> <chr>      <dbl>       <dbl>
 1     0 2013-01-01         1 AUTOMOTIVE     0           0
 2  1782 2013-01-02         1 AUTOMOTIVE     2           0
 3  3564 2013-01-03         1 AUTOMOTIVE     3           0
 4  5346 2013-01-04         1 AUTOMOTIVE     3           0
 5  7128 2013-01-05         1 AUTOMOTIVE     5           0
 6  8910 2013-01-06         1 AUTOMOTIVE     2           0
 7 10692 2013-01-07         1 AUTOMOTIVE     0           0
 8 12474 2013-01-08         1 AUTOMOTIVE     2           0
 9 14256 2013-01-09         1 AUTOMOTIVE     2           0
10 16038 2013-01-10         1 AUTOMOTIVE     2           0
# ℹ 3,000,878 more rows
# A tibble: 0 × 3
# ℹ 3 variables: store_nbr <dbl>, family <chr>, .gaps <lgl>
# A tibble: 4 × 1
  .from     
  <date>    
1 2013-12-25
2 2014-12-25
3 2015-12-25
4 2016-12-25

Tssible final (train)

train_tsbl <- train_tsbl |> 
  fill_gaps(.full = TRUE, 
            sales = 0L, 
            onpromotion = 0L)

train_tsbl
# A tsibble: 3,008,016 x 6 [1D]
# Key:       store_nbr, family [1,782]
      id date       store_nbr family     sales onpromotion
   <dbl> <date>         <dbl> <chr>      <dbl>       <dbl>
 1     0 2013-01-01         1 AUTOMOTIVE     0           0
 2  1782 2013-01-02         1 AUTOMOTIVE     2           0
 3  3564 2013-01-03         1 AUTOMOTIVE     3           0
 4  5346 2013-01-04         1 AUTOMOTIVE     3           0
 5  7128 2013-01-05         1 AUTOMOTIVE     5           0
 6  8910 2013-01-06         1 AUTOMOTIVE     2           0
 7 10692 2013-01-07         1 AUTOMOTIVE     0           0
 8 12474 2013-01-08         1 AUTOMOTIVE     2           0
 9 14256 2013-01-09         1 AUTOMOTIVE     2           0
10 16038 2013-01-10         1 AUTOMOTIVE     2           0
# ℹ 3,008,006 more rows

Modelo ETS (mejor resultado)

tictoc::tic()
fit_ETS <- train_tsbl |> 
  model(
    ETS = ETS(sales ~ error("A") + trend("Ad") + season("A"))
  )
tictoc::toc()
202.751 sec elapsed
glance(fit_ETS)
# A tibble: 1,782 × 11
   store_nbr family  .model  sigma2 log_lik    AIC   AICc    BIC     MSE    AMSE
       <dbl> <chr>   <chr>    <dbl>   <dbl>  <dbl>  <dbl>  <dbl>   <dbl>   <dbl>
 1         1 AUTOMO… ETS    6.40e+0  -7833. 15692. 15692. 15763. 6.36e+0 6.36e+0
 2         1 BABY C… ETS    0          Inf   -Inf   -Inf   -Inf  0       0      
 3         1 BEAUTY  ETS    3.12e+0  -7225. 14476. 14477. 14547. 3.09e+0 3.11e+0
 4         1 BEVERA… ETS    1.17e+5 -16116. 32258. 32258. 32329. 1.16e+5 1.34e+5
 5         1 BOOKS   ETS    2.05e-1  -4927.  9880.  9880.  9951. 2.03e-1 2.06e-1
 6         1 BREAD/… ETS    4.03e+3 -13273. 26572. 26573. 26643. 4.00e+3 4.13e+3
 7         1 CELEBR… ETS    1.06e+3 -12148. 24323. 24323. 24393. 1.06e+3 1.06e+3
 8         1 CLEANI… ETS    1.82e+4 -14547. 29119. 29119. 29190. 1.81e+4 1.80e+4
 9         1 DAIRY   ETS    1.26e+4 -14237. 28501. 28501. 28572. 1.26e+4 1.30e+4
10         1 DELI    ETS    7.43e+2 -11845. 23716. 23716. 23786. 7.37e+2 7.45e+2
# ℹ 1,772 more rows
# ℹ 1 more variable: MAE <dbl>

Genración de pronóstico

tictoc::tic()

fcst_ets <- fit_ETS |> 
  forecast(h = 16)
 
tictoc::toc()
6.793 sec elapsed
fcst_ets
# A fable: 28,512 x 6 [1D]
# Key:     store_nbr, family, .model [1,782]
   store_nbr family     .model date             sales .mean
       <dbl> <chr>      <chr>  <date>          <dist> <dbl>
 1         1 AUTOMOTIVE ETS    2017-08-16 N(4.8, 6.4)  4.79
 2         1 AUTOMOTIVE ETS    2017-08-17 N(4.3, 6.4)  4.35
 3         1 AUTOMOTIVE ETS    2017-08-18   N(5, 6.4)  5.02
 4         1 AUTOMOTIVE ETS    2017-08-19   N(5, 6.4)  4.99
 5         1 AUTOMOTIVE ETS    2017-08-20 N(2.8, 6.4)  2.82
 6         1 AUTOMOTIVE ETS    2017-08-21 N(4.6, 6.4)  4.60
 7         1 AUTOMOTIVE ETS    2017-08-22 N(4.9, 6.4)  4.93
 8         1 AUTOMOTIVE ETS    2017-08-23 N(4.8, 6.4)  4.80
 9         1 AUTOMOTIVE ETS    2017-08-24 N(4.4, 6.4)  4.36
10         1 AUTOMOTIVE ETS    2017-08-25   N(5, 6.4)  5.03
# ℹ 28,502 more rows

Kaggle

Cargando el test

test <- read_csv("test.csv")
test
# A tibble: 28,512 × 5
        id date       store_nbr family       onpromotion
     <dbl> <date>         <dbl> <chr>              <dbl>
 1 3000888 2017-08-16         1 AUTOMOTIVE             0
 2 3000889 2017-08-16         1 BABY CARE              0
 3 3000890 2017-08-16         1 BEAUTY                 2
 4 3000891 2017-08-16         1 BEVERAGES             20
 5 3000892 2017-08-16         1 BOOKS                  0
 6 3000893 2017-08-16         1 BREAD/BAKERY          12
 7 3000894 2017-08-16         1 CELEBRATION            0
 8 3000895 2017-08-16         1 CLEANING              25
 9 3000896 2017-08-16         1 DAIRY                 45
10 3000897 2017-08-16         1 DELI                  18
# ℹ 28,502 more rows

Generando archivo de carga

submission <- fcst_ets |> 
  left_join(test, by = c("date", "store_nbr", "family")) |> 
  as_tibble() |> 
  select(id, .mean) |> 
  rename(sales = .mean)
submission
# A tibble: 28,512 × 2
        id sales
     <dbl> <dbl>
 1 3000888  4.79
 2 3002670  4.35
 3 3004452  5.02
 4 3006234  4.99
 5 3008016  2.82
 6 3009798  4.60
 7 3011580  4.93
 8 3013362  4.80
 9 3015144  4.36
10 3016926  5.03
# ℹ 28,502 more rows
submission |> 
  write_csv("submission.csv")

Conclusión

Básicamente los mejores modelos que obtuvimos siempre incluían ETS dentro de la combinación, o solo el ETS con los parámetros indicados. Consideramos que esto se debe a que individualmente la mayoría de las series se adaptaban bien a este modelo, a pesar de que con parámetros específicos para cada serie, sin duda hubiera sido mejor. Creemos que el ETS se adapta de buena forma, porque al ser ventas de tiendas los datos que estamos utilizando, suelen tener una tendencia, e incluso una estacionalidad que se va repitiendo cada cierto tiempo por las épocas del año. Este modelo al capturar tanto tendencia como estacionalidad, y poder manejar tanto errores como datos faltantes, creímos desde un inicio que podría dar buenos resultados, y fue el que se terminó adaptando mejor.