How to unnest samples from a fable R forecast model

273 views Asked by At

I am trying to get the samples from a forecast model generated with fable. This is what I tried

library(fable)
library(tsibble)
library(tsibbledata)
library(dplyr)
library(tidyr)

# Forecasting with an ETS(M,Ad,A) model to Australian beer production
beer_fc <- aus_production %>%
  model(ets = ETS(log(Beer) ~ error("M") + trend("Ad") + season("A"))) %>%
  forecast(h = "3 years", bootstrap=TRUE, times = 5)

beer_fc %>% unnest(c(Beer))

The error I get is:

Error: Input must be list of vectors

Here is the structure of the data str(beer_fc$Beer[1]):

> str(beer_fc$Beer[1])
dist [1:1] 
$ :List of 3
 ..$ dist     :List of 1
 .. ..$ x: num [1:5] 6.09 6.02 6.06 6 5.95
 .. ..- attr(*, "class")= chr [1:2] "dist_sample" "dist_default"
 ..$ transform:function (.x)  
 .. ..- attr(*, "class")= chr "transformation"
 .. ..- attr(*, "inverse")=function (.x)  
 ..$ inverse  :function (.x)  
 ..- attr(*, "class")= chr [1:2] "dist_transformed" "dist_default"
@ vars: chr "Beer"
3

There are 3 answers

0
akrun On BEST ANSWER

If we want to extract the 'dist' values into 'long' format, loop over the list column 'Beer', extract the values, assign it back to the 'Beer' and then unnest

library(purrr)
library(tidyr)
library(dplyr)
beer_fc$Beer <- map(beer_fc$Beer, ~ .x[[1]]$x)
beer_fc %>%
       unnest(c(Beer))

-output

# A tibble: 60 x 4
#   .model Quarter  Beer .mean
#   <chr>    <qtr> <dbl> <dbl>
# 1 ets    2010 Q3  6.02  402.
# 2 ets    2010 Q3  5.99  402.
# 3 ets    2010 Q3  6.05  402.
# 4 ets    2010 Q3  5.92  402.
# 5 ets    2010 Q3  5.99  402.
# 6 ets    2010 Q4  6.15  470.
# 7 ets    2010 Q4  6.15  470.
# 8 ets    2010 Q4  6.17  470.
# 9 ets    2010 Q4  6.17  470.
#10 ets    2010 Q4  6.12  470.
# … with 50 more rows
0
Ronak Shah On

You can use pluck to get values that you want to extract from any level and then unnest.

library(tidyverse)

beer_fc %>%
  mutate(value = map(Beer, purrr::pluck, 'dist', 'x')) %>%
  unnest(value)

# A tibble: 60 x 5
#   .model Quarter         Beer .mean value
#   <chr>    <qtr>       <dist> <dbl> <dbl>
# 1 ets    2010 Q3 t(sample[5])  402.  6.00
# 2 ets    2010 Q3 t(sample[5])  402.  6.02
# 3 ets    2010 Q3 t(sample[5])  402.  5.99
# 4 ets    2010 Q3 t(sample[5])  402.  6.05
# 5 ets    2010 Q3 t(sample[5])  402.  5.92
# 6 ets    2010 Q4 t(sample[5])  483.  6.21
# 7 ets    2010 Q4 t(sample[5])  483.  6.16
# 8 ets    2010 Q4 t(sample[5])  483.  6.14
# 9 ets    2010 Q4 t(sample[5])  483.  6.22
#10 ets    2010 Q4 t(sample[5])  483.  6.16
# … with 50 more rows
0
Mitchell O'Hara-Wild On

The {distributional} package (used to provide these distribution objects) has since been updated with functions to obtain the shape and parameters of a distribution. These functions are recommended instead of unclassing the distributions, as the internal representation of these distributions may change in the future.

For example, take a Normal distribution:

library(distributional)
fc <- dist_normal(10, 3)

Obtain the parameters from the distribution

parameters(fc)
#>   mu sigma
#> 1 10     3

Obtain the shape of the distribution

family(fc)
#> [1] "normal"

For your example…

library(fable)
#> Loading required package: fabletools
beer_fc <- tsibbledata::aus_production %>%
  model(ets = ETS(log(Beer) ~ error("M") + trend("Ad") + season("A"))) %>%
  forecast(h = "3 years", bootstrap=TRUE, times = 5)

You could extract the parameters and family

library(dplyr)
#> 
#> Attaching package: 'dplyr'
#> The following objects are masked from 'package:stats':
#> 
#>     filter, lag
#> The following objects are masked from 'package:base':
#> 
#>     intersect, setdiff, setequal, union
beer_fc %>% 
  mutate(parameters(Beer), family(Beer))
#> # A fable: 12 x 6 [1Q]
#> # Key:     .model [1]
#>    .model Quarter      Beer .mean x         `family(Beer)`
#>    <chr>    <qtr>    <dist> <dbl> <list>    <chr>         
#>  1 ets    2010 Q3 sample[5]  411. <dbl [5]> sample        
#>  2 ets    2010 Q4 sample[5]  486. <dbl [5]> sample        
#>  3 ets    2011 Q1 sample[5]  426. <dbl [5]> sample        
#>  4 ets    2011 Q2 sample[5]  382. <dbl [5]> sample        
#>  5 ets    2011 Q3 sample[5]  409. <dbl [5]> sample        
#>  6 ets    2011 Q4 sample[5]  487. <dbl [5]> sample        
#>  7 ets    2012 Q1 sample[5]  424. <dbl [5]> sample        
#>  8 ets    2012 Q2 sample[5]  390. <dbl [5]> sample        
#>  9 ets    2012 Q3 sample[5]  407. <dbl [5]> sample        
#> 10 ets    2012 Q4 sample[5]  483. <dbl [5]> sample        
#> 11 ets    2013 Q1 sample[5]  425. <dbl [5]> sample        
#> 12 ets    2013 Q2 sample[5]  390. <dbl [5]> sample

Now the x variable contains a simple list of numbers that you can use unnest() or other functions to work with.

Created on 2022-11-15 by the reprex package (v2.0.1)