Rolling Exponential Smoothing

669 views Asked by At

REWRITING ORIGINAL QUESTION

I want a function that takes a vector and pre-defined exponential smoothing model (in this example, simple exponential smoothing with alpha = 0.5), and does one-step ahead forecasting on the input vector. The below code, though clunky, does what I want. Is there a better way to do this, or a built in function / package function that does this?

The second part to this question is: If I fit an ETS or ARIMA model with, say, the {fable} package, is there a function that can take the fitted ETS/ARIMA model and do the same one-step-ahead forecasting on a vector, like in the first part?

# Ref: # https://stats.stackexchange.com/questions/44984/how-do-you-use-simple-exponential-smoothing-in-r
# NOT fully tested, just in this case.  Gives one-step-ahead forecasts for an exponential smoothing model
ses <- function(x, alpha, beta = FALSE, gamma = FALSE) {
    ## Populate this vector with return values
    result_vec <- numeric(length(x))
    result_vec[1] <- NA

    for (i in 2:length(x)) {
        mod <- HoltWinters(x[seq(i)], alpha=alpha, beta=beta, gamma=gamma)
        result_vec[i] <- predict(mod, n.ahead = 1)
    }
    result_vec
}

new_wt <- c(1, 0, 0, 0, 0, 1, 1, 1)
ses(new_wt, 0.5)
#> [1]        NA 0.5000000 0.2500000 0.1250000 0.0625000 0.5312500 0.7656250
#> [8] 0.8828125

Created on 2020-10-22 by the reprex package (v0.3.0)

1

There are 1 answers

0
mpettis On

This is the question and post I was looking for that solved it for me:

https://stats.stackexchange.com/questions/265115/one-step-ahead-forecast https://robjhyndman.com/hyndsight/out-of-sample-one-step-forecasts/

I was then able to leverage the forecast::ets() model builder to build what I want for a filter, and then use the technique there of re-calling ets() with the new data I want to do one-step-ahead forecasts on (and the original model), and then call fitted() on that new model to get the one-step-ahead forecasts. It matches up close enough with what I want a filter to do (with some off-by-one differences in the output that I can deal with easily enough).

It mostly worked with the {fable} package ETS() call. However, I don't know how to specify the starting values to make sure we match. But it is pretty close overall, and over time, should roughly match.

Below is sample code with what I had and what the ultimate solution was in the end.

# Ref: # https://stats.stackexchange.com/questions/44984/how-do-you-use-simple-exponential-smoothing-in-r
# Hand-rolled solution
# NOT fully tested, just in this case.  Gives one-step-ahead forecasts for an exponential smoothing model
ses <- function(x, alpha, beta = FALSE, gamma = FALSE) {
    ## Populate this vector with return values
    result_vec <- numeric(length(x))
    result_vec[1] <- NA

    for (i in 2:length(x)) {
        ## One method
        mod <- HoltWinters(x[seq(i)], alpha=alpha, beta=beta, gamma=gamma)
        result_vec[i] <- predict(mod, n.ahead = 1)
        
        ## A similar method
        # result_vec[i] <- forecast::ses(x[seq(i)], alpha=alpha, beta=beta, gamma=gamma, h=1)$mean
    }
    result_vec
}

new_wt <- c(1, 0, 0, 0, 0, 1, 1, 1)
ses(new_wt, 0.5)
#> [1]        NA 0.5000000 0.2500000 0.1250000 0.0625000 0.5312500 0.7656250
#> [8] 0.8828125


## From: https://robjhyndman.com/hyndsight/out-of-sample-one-step-forecasts/
## I can do one-step-ahead forecasts with the forecast package
library(forecast)
#> Registered S3 method overwritten by 'quantmod':
#>   method            from
#>   as.zoo.data.frame zoo
#> 
#> Attaching package: 'forecast'
#> The following object is masked _by_ '.GlobalEnv':
#> 
#>     ses

## Values to do one-step-ahead forecasts on
new_wt <- c(1, 0, 0, 0, 0, 1, 1, 1)

## Fit a model with hand-picked parameters, in this case, and walk the forecast
## ahead a step at a time.
initial_value <- 0
fit <- forecast::ets(initial_value, model="ANN", alpha=0.5, use.initial.values = T)
fit2 <- forecast::ets(new_wt, model=fit, use.initial.values = T)
fitted(fit2) %>% as.vector()
#> [1] 0.0000000 0.5000000 0.2500000 0.1250000 0.0625000 0.0312500 0.5156250
#> [8] 0.7578125



## With fable, I  can't seem to make it work:
library(fable)
#> Loading required package: fabletools
#> 
#> Attaching package: 'fabletools'
#> The following objects are masked from 'package:forecast':
#> 
#>     accuracy, forecast
library(tibble)

new_wt_ts <-
    tibble(value = new_wt, idx = seq(length(new_wt))) %>%
    as_tsibble(index = idx)

myfable <-
    model(new_wt_ts, ets = ETS(value ~ error("A") + trend("N", alpha=0.5) + season("N")))

## This is close to the others, and goes in the right direction, not sure why it doesn't match?
fitted(myfable, new_wt_ts)
#> # A tsibble: 8 x 3 [1]
#> # Key:       .model [1]
#>   .model   idx .fitted
#>   <chr>  <int>   <dbl>
#> 1 ets        1  0.531 
#> 2 ets        2  0.765 
#> 3 ets        3  0.383 
#> 4 ets        4  0.191 
#> 5 ets        5  0.0957
#> 6 ets        6  0.0478
#> 7 ets        7  0.524 
#> 8 ets        8  0.762

Created on 2020-10-22 by the reprex package (v0.3.0)