2

I am forecasting several models on a nested (grouped) df. My issue is solved if I apply sw_glance to each list-column separately, but, for my example, if I am applying 6 models, then it is asking me to mutate six times. I have spent countless hours and I think I am almost there. Why can't I do the line below and overwrite the existing variables with the new values the function brings? (I included a reprex below, where step 5 is where I am getting stuck)

models_df%<>% map(~mutate_at(.x,vars(mod_ets,mod_hw)),sw_glance)

Just to name a few, here is the list:

-tidyverse documentation, where it mentioned that for grouped variables, mutate_at would fail, unless I add -group_cols(). No go.

-purrr documentation: I tried pmap passing a list of variables. I tried map in combination with mutate_at. I tried mutate_at by itself. I have tried naming the function (.f ...) and anonymous one (~..), but nothing

-I tried here several articles, that almost got me there. I upgraded to tidyr 1.0 and can include my sessionInfo() if needed.

#1 dummy df
df=tibble(Tag=seq(as.Date("2010-01-01"),by="month", length.out = 60), gatos=sample(c("a","b"),60, replace = T), sales=runif(60))

#2 nesting 
nested_df= df %>% 
  group_by(gatos) %>% 
  nest()

#3 declaring time series
ts_vector = nested_df %>%
  mutate(data.ts=map(data,tk_ts,select=-Tag,start=c(2010,01),freq=12))

# Step 4: Apply models
models_df = ts_vector %>% 
  mutate(mod_ets = map(data.ts,ets),
         mod_hw = map(data.ts,HoltWinters))

# Step 5: Apply sw_glance (Does NOT work)
models_df %<>%
map(~mutate_at(.x,vars(mod_ets,mod_hw)),sw_glance)

Error in UseMethod("tbl_vars") : 
  no applicable method for 'tbl_vars' applied to an object of class "character"

# This DOES work
models_df %<>% 
  mutate(foo_ets=map(mod_ets,sw_glance),
         foo_hw=map(mod_hw,sw_glance))

I would expect that mutate_at modifies the existing variables without having to add new ones. Otherwise, I would appreciate how to apply sw_glance to several models in one-go if possible. Thank you guys. I really appreciate your help.

Ronak Shah
  • 377,200
  • 20
  • 156
  • 213
Will
  • 57
  • 4

1 Answers1

2

We can write a function to apply sw_glance to each model

library(tidyverse)

apply_models <- function(list_model) map(list_model, sweep::sw_glance)

and apply it to multiple columns using mutate_at

models_df %>% mutate_at(vars(mod_ets, mod_hw), apply_models)

#  gatos           data data.ts mod_ets           mod_hw           
#  <chr> <list<df[,2]>> <list>  <list>            <list>           
#1 b           [31 × 2] <ts>    <tibble [1 × 12]> <tibble [1 × 12]>
#2 a           [29 × 2] <ts>    <tibble [1 × 12]> <tibble [1 × 12]>
Ronak Shah
  • 377,200
  • 20
  • 156
  • 213
  • Hi @Ronak! Thank you very much for this approach. While it works, it creates more columns. Above in my text I mentioned I was looking to affect/replace(let's call it overwrite) mod_ets and mod_hw with the new values that sw_glance would bring once we apply that function. Any thoughts on that one? – Will Sep 30 '19 at 04:26
  • 1
    @Will ohh..I thought you were specifically looking for new columns in your original dataframe. In that case, you can do `models_df %>% mutate_at(vars(mod_ets, mod_hw), apply_models)`. Is this what you meant? – Ronak Shah Sep 30 '19 at 04:29
  • ! I just modified the text by removing the "foo" from the function and now it works by overwriting the two current variables. So, that's taken care of. Any thoughts as to why I cannot just apply the sw_glance directly and have to write a function instead? – Will Sep 30 '19 at 04:33
  • It seems you were responding when I was telling about it...lol :) – Will Sep 30 '19 at 04:34
  • 1
    `sw_glance` accepts only one model at a time. As we are passing multiple models (column) to it we need to use `map` (or `lapply`) which will pass each model one at a time. – Ronak Shah Sep 30 '19 at 04:36
  • In other words, sw_glance can only take one model (i.e one column) at a time and therefore, to make it accepts more than one model, the columns (mod_ets and mod_hw) needed to be converted to a list, is that right? Now, I was using map to loop through each row of the columns specified within mutate_at. – Will Sep 30 '19 at 04:44
  • 1
    No..not exactly. One column != one model. In fact, for every column we have multiple models i.e equal to number of rows. For the example shared, we have got 2 models each in column `mod_ets` and `mod_hw`. Using `mutate_at`, we are looping over each column mentioned in `vars` and with `map` we are looping over each value in those columns. – Ronak Shah Sep 30 '19 at 04:49
  • Outstanding Ronak! Thank you very much for your wisdom. Problem successfully solved! – Will Sep 30 '19 at 04:54