Search code examples
rfor-looptidyverse

Loop output to list. Is there an elegant alternative?


In order to get the accuracy values from a forecast output vs. actual values in long format with many models and id's, I wanted to loop through the data and iteratively reduce the input object by using tail(input_object, -Forecast_horizon).

I would rather prefer some tidy approach to do this, because looping like this seems odd and crude.

library(forecast)
library(tibble)
testing_frame <- tibble(.value = rep(c(11,32,35,57,67,34),12),
                            test_value = rep(c(12,33,40,60,69,44),12),
                        id = rep(as.factor(c(rep(1,6),rep(2,6),rep(3,6),rep(4,6),rep(5,6),rep(6,6))),2),
                        model = as.character(c(rep(1,36),c(rep(2,36)))))

H = 6
iter = c(1:12)
datalist = list()
i = 1

for (i in iter) {
    acc_all = forecast::accuracy(ts(head(testing_frame$.value,frequency = H),n=H),
                                 ts(head(testing_frame$test_value,frequency = H),n=H))
    testing_frame <- tail(testing_frame, -H)
    acc_all_out = acc_all[,7]
    datalist[[i]] <- acc_all_out 
}
output = do.call(rbind, datalist)

Solution

  • A somewhat more succint approach would be to use data frame unpacking in summarise() to create new columns for each metric returned by accuracy():

    library(tidyverse)
    library(forecast)
    
    testing_frame %>% 
      group_by(id, model) %>% 
      summarise(
        accuracy(
          ts(.value, frequency = H),
          ts(test_value, frequency = H)
        ) %>% as_tibble()
      )
    #> # A tibble: 12 x 9
    #> # Groups:   id [6]
    #>    id    model    ME  RMSE   MAE   MPE  MAPE   ACF1 `Theil's U`
    #>    <fct> <chr> <dbl> <dbl> <dbl> <dbl> <dbl>  <dbl>       <dbl>
    #>  1 1     1      3.67  4.83  3.67  9.08  9.08 -0.114       0.128
    #>  2 1     2      3.67  4.83  3.67  9.08  9.08 -0.114       0.128
    #>  3 2     1      3.67  4.83  3.67  9.08  9.08 -0.114       0.128
    #>  4 2     2      3.67  4.83  3.67  9.08  9.08 -0.114       0.128
    #>  5 3     1      3.67  4.83  3.67  9.08  9.08 -0.114       0.128
    #>  6 3     2      3.67  4.83  3.67  9.08  9.08 -0.114       0.128
    #>  7 4     1      3.67  4.83  3.67  9.08  9.08 -0.114       0.128
    #>  8 4     2      3.67  4.83  3.67  9.08  9.08 -0.114       0.128
    #>  9 5     1      3.67  4.83  3.67  9.08  9.08 -0.114       0.128
    #> 10 5     2      3.67  4.83  3.67  9.08  9.08 -0.114       0.128
    #> 11 6     1      3.67  4.83  3.67  9.08  9.08 -0.114       0.128
    #> 12 6     2      3.67  4.83  3.67  9.08  9.08 -0.114       0.128