Home > Software design >  R - unpacking and loop model fitting
R - unpacking and loop model fitting

Time:10-03

I am currently in a scenario where I need to fit multiple models where I just change one of the parameters.

library(fpp3)

gas <- us_gasoline %>% filter(year(Week) <= 2004)
gas %>% autoplot(Barrels)
fit <- gas %>%
  model(
    fourier1 = TSLM(Barrels ~ trend()   fourier(K = 1)),
    fourier2 = TSLM(Barrels ~ trend()   fourier(K = 2)),
    fourier3 = TSLM(Barrels ~ trend()   fourier(K = 3)),
    fourier4 = TSLM(Barrels ~ trend()   fourier(K = 4)),
    fourier5 = TSLM(Barrels ~ trend()   fourier(K = 5)),
    fourier6 = TSLM(Barrels ~ trend()   fourier(K = 6)),
    fourier7 = TSLM(Barrels ~ trend()   fourier(K = 7)),
    fourier8 = TSLM(Barrels ~ trend()   fourier(K = 8)),
    fourier9 = TSLM(Barrels ~ trend()   fourier(K = 9))
  )

I would like to have a loop from 1 to n and create a model definition for each of the values of K that I would then feed to the function model. I would like to store the model definitions in a dictionary (list) where I would have separately the model name and the model itself.

Thus far I have been able to create single model formuas and feed them to the function model in a successful manner:

form <- as.formula("Barrels ~ trend()   fourier(K = 1)")
mod <- TSLM(form)

gas %>% 
  model(
    mod
  )

My goal would be to have a set of model definitions created in a loop and stored in a list, which I would then feed to the function model as arguments

# Create model definitions
mods <- list()
for (i in seq(1, 9)) {            
  form <- paste0("Barrels ~ trend()   fourier(K = ", as.character(i), ")")
  mods[[paste0("model_name_", as.character(i))]] <- TSLM(form)
}

In python I would use list unpacking or dict unpacking to achieve this, but I fail to attain this in R. People suggest using do.call() but I fail to do this...

Could anybody please help?

CodePudding user response:

EDIT After discussion with the OP I decided to propose a solution using injection operator !!:

library(glue)

vec <- c(1:9)
form <- glue("Barrels ~ trend()   fourier(K = {vec})")
model_nm <- glue("model_name_{vec}")


map2_dfc(model_nm, form, ~ gas %>% model(!!{.x} := TSLM(formula(.y))))

# A mable: 1 x 9
  model_name_1 model_name_2 model_name_3 model_name_4 model_name_5 model_name_6 model_name_7
       <model>      <model>      <model>      <model>      <model>      <model>      <model>
1       <TSLM>       <TSLM>       <TSLM>       <TSLM>       <TSLM>       <TSLM>       <TSLM>
# … with 2 more variables: model_name_8 <model>, model_name_9 <model>

First Answer I made a slight modifications to your own code adding formula function to extract formula from your character definitions. As soon as we have a list of mable objects we can apply any function such as fabletools::forecast on each element with purrr::map:

library(purrr)
library(fable)
library(fpp3)

# Create model definitions
mods <- list()

for (i in seq(1, 9)) {            
  form <- paste0("Barrels ~ trend()   fourier(K = ", as.character(i), ")")
  mods[[paste0("model_name_", as.character(i))]] <- gas %>%
    model(fourier1 = TSLM(formula(form)))
}


map(mods, forecasts)

CodePudding user response:

What about something that looks like this. Here we map the numbers you are looking for (k values), then we pivot_wider to get the desired output structure.

library(tidyverse)
library(fpp3)


gas <- us_gasoline %>% filter(year(Week) <= 2004)


tibble(K = 1:9) |>
  mutate(mod = map(K, \(k){
           form <- as.formula(paste0("Barrels ~ trend()   fourier(K =", k, ")"))
           mod <- TSLM(form)
           gas |>
             model(mod)|>
             pull(mod)
         })) |>
  pivot_wider(names_from = K, values_from = mod, names_prefix = "fourier")
#> # A tibble: 1 x 9
#>   fourier1      fourier2      fourier3  fourier4  fourier5  fourier6  fourier7 
#>   <list>        <list>        <list>    <list>    <list>    <list>    <list>   
#> 1 <lst_mdl [1]> <lst_mdl [1]> <lst_mdl> <lst_mdl> <lst_mdl> <lst_mdl> <lst_mdl>
#> # ... with 2 more variables: fourier8 <list>, fourier9 <list>
  • Related