All fable models with formula-based model specification support a highly flexible specification of transformations. Specified transformations are automatically back-transformed and bias adjusted to produce forecast means and fitted values on the original scale of the data.

The transformation used for the model is defined on the left of the tilde (~) in the formula. For example, when forecasting Melbourne Trips from the tsibble::tourism dataset, a square root transformation can applied using sqrt(Trips).

library(fable)
#> Loading required package: fabletools
#> Registered S3 method overwritten by 'tsibble':
#>   method               from 
#>   as_tibble.grouped_df dplyr
library(tsibble)
#> 
#> Attaching package: 'tsibble'
#> The following objects are masked from 'package:base':
#> 
#>     intersect, setdiff, union
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
tourism %>%
  filter(Region == "Melbourne") %>% 
  model(ETS(sqrt(Trips)))
#> # A mable: 4 x 4
#> # Key:     Region, State, Purpose [4]
#>   Region    State    Purpose  `ETS(sqrt(Trips))`
#>   <chr>     <chr>    <chr>               <model>
#> 1 Melbourne Victoria Business       <ETS(A,N,A)>
#> 2 Melbourne Victoria Holiday        <ETS(A,A,A)>
#> 3 Melbourne Victoria Other          <ETS(A,N,N)>
#> 4 Melbourne Victoria Visiting       <ETS(M,N,A)>

Combining transformations

Multiple transformations can be combined using this interface, allowing more complicated transformations to be used. A simple example of a combined transformation is f(x)=log(x+1)f(x) = log(x+1), as it involves both a log transformation, and a +1 transformation. This transformation is commonly used to overcome a limitation of using log transformations to preserve non-negativity, on data which contains zeroes.

Simple combined transformations and backtransformations can be constructed automatically.

library(tsibble)
tourism %>%
  filter(Region == "Melbourne") %>% 
  model(ETS(log(Trips + 1)))
#> # A mable: 4 x 4
#> # Key:     Region, State, Purpose [4]
#>   Region    State    Purpose  `ETS(log(Trips + 1))`
#>   <chr>     <chr>    <chr>                  <model>
#> 1 Melbourne Victoria Business          <ETS(A,N,A)>
#> 2 Melbourne Victoria Holiday           <ETS(M,A,A)>
#> 3 Melbourne Victoria Other             <ETS(A,N,N)>
#> 4 Melbourne Victoria Visiting          <ETS(M,N,A)>

Custom transformations

It is possible to extend the supported transformations by defining your own transformation with an appropriate back-transformation function. It is assumed that the first argument of your function is your data which is being transformed.

A useful transformation which is not readily supported by fable is the scaled logit, which allows the forecasts to be bounded by a given interval (forecasting within limits). The appropriate transformation to ensure the forecasted values are between aa and bb (where a<ba<b) is given by:

f(x)=log(xabx)f(x) = \log\left(\dfrac{x-a}{b-x}\right)

Inverting this transformation gives the appropriate back-transformation of:

f1(x)=a+bex1+ex=(ba)ex1+ex+af^{-1}(x) = \dfrac{a + be^x}{1 + e^x} = \dfrac{(b-a)e^x}{1 + e^x} + a To use this transformation for modelling, we can pair the transformation with its back transformation using the new_transformation function from fabletools. This function which accepts two inputs: first the transformation, and second the back-transformation.

scaled_logit <- function(x, lower=0, upper=1){
  log((x-lower)/(upper-x))
}
inv_scaled_logit <- function(x, lower=0, upper=1){
  (upper-lower)*exp(x)/(1+exp(x)) + lower
}
my_scaled_logit <- new_transformation(scaled_logit, inv_scaled_logit)

Once you define your transformation as above, it is ready to use anywhere you would normally use a transformation.

cbind(mdeaths, fdeaths) %>%
  as_tsibble(pivot_longer = FALSE) %>% 
  model(ETS(my_scaled_logit(mdeaths, 750, 3000) ~
              error("A") + trend("N") + season("A"))) %>%
  report()
#> Series: mdeaths 
#> Model: ETS(A,N,A) 
#> Transformation: my_scaled_logit(mdeaths, 750, 3000) 
#>   Smoothing parameters:
#>     alpha = 0.1427297 
#>     gamma = 0.0001000037 
#> 
#>   Initial states:
#>       l[0]      s[0]      s[-1]      s[-2]     s[-3]     s[-4]      s[-5]
#>  -0.576581 0.7181113 -0.1305675 -0.4690919 -1.197746 -1.114423 -0.7727465
#>       s[-6]     s[-7]     s[-8]     s[-9]   s[-10]   s[-11]
#>  -0.6240044 -0.275529 0.4140919 0.9658113 1.272782 1.213311
#> 
#>   sigma^2:  0.1489
#> 
#>      AIC     AICc      BIC 
#> 185.2488 193.8202 219.3988

Forecast means and medians

When forecasting with transformations, the model is fitted and forecasted using the transformed data. To produce forecasts of the original data, the predicted values must be back-transformed. However this process of predicting transformed data and backtransforming predictions usually results in producing forecast medians. To convert the forecast medians into forecast means, a transformation bias adjustment is required:

ŷ=f1(ỹ)+12σ22ỹ2f1(ỹ)\hat{y} = f^{-1}(\tilde{y}) + \dfrac{1}{2}\sigma^2\dfrac{\partial^2}{\partial \tilde{y}^2}f^{-1}(\tilde{y}) Note that the forecast medians are given by f1(ỹ)f^{-1}(\tilde{y}), and the adjustment needed to produce forecast means (ŷ\hat{y}) is 12σ22ỹ2f1(ỹ)\dfrac{1}{2}\sigma^2\dfrac{\partial^2}{\partial \tilde{y}^2}f^{-1}(\tilde{y}).

The fable package automatically produces forecast means (by back-transforming and adjusting the transformed forecasts). The forecast medians can be obtained via the forecast intervals when level=0.

More information about adjusting forecasts to compute forecast means can be found at the forecast mean after back-transformation.