4.3 Fitting with ets()
The forecast package will fit a wide variety of exponential smoothing models. The main fitting function is ets()
:
ets(y, model = "ZZZ", < + many other arguments >)
y : your data. A time series of responses.
model: what type of exponential smoothing model.
We are going to use ets()
to fit three simple types of exponential smoothing models:
model | “ZZZ” | alternate function |
---|---|---|
exponential smoothing no trend | “ANN” | ses() |
exponential smoothing with trend | “AAN” | holt() |
exponential smoothing choose trend | “AZN” | NA |
The alternate function does exactly the same fitting. It is just a ‘shortcut’.
4.3.1 Exponential smoothing with no trend
This is like the naive model that just uses the last value to make the forecast, but instead of only using the last value it will use values farther in the past also. The weighting fall off exponentially.
Load the data and forecast package.
load("landings.RData")
fit <- forecast::ets(anchovy87ts, model="ANN")
fr <- forecast::forecast(fit, h=5)
plot(fr)
Look at the estimates
fit
## ETS(A,N,N)
##
## Call:
## forecast::ets(y = anchovy87ts, model = "ANN")
##
## Smoothing parameters:
## alpha = 0.7065
##
## Initial states:
## l = 8.5553
##
## sigma: 0.2166
##
## AIC AICc BIC
## 6.764613 7.964613 10.298775
4.3.2 The weighting function
4.3.3 Produce forecast using a previous fit
Say you want to estimate a forecasting model from one dataset and use that model to forecast another dataset or another area. Here is how to do that.
This is the fit to the 1964-1987 data:
fit1 <- forecast::ets(anchovy87ts, model="ANN")
Use that model with the 2000-2007 data and produce a forecast:
dat <- subset(landings, Species=="Anchovy" & Year>=2000 & Year<=2007)
dat <- ts(dat$log.metric.tons, start=2000)
fit2 <- forecast::ets(dat, model=fit1)
## Model is being refit with current smoothing parameters but initial states are being re-estimated.
## Set 'use.initial.values=TRUE' if you want to re-use existing initial values.
fr2 <- forecast::forecast(fit2, h=5)
plot(fr2)
4.3.4 Naive model with drift
Fit a model that uses the last observation as the forecast but includes a trend estimated from ALL the data. This is what the naive model with drift does.
fit.rwf <- forecast::Arima(anchovy87ts, order=c(0,1,0), include.drift=TRUE)
fr.rwf <- forecast::forecast(fit.rwf, h=5)
plot(fr.rwf)
The trend seen in the blue line is estimated from the overall trend in ALL the data.
coef(fit.rwf)
## drift
## 0.06577281
The trend from all the data is (last-first)/(number of steps).
mean(diff(anchovy87ts))
## [1] 0.06577281
So we only use the latest data to choose the level for our forecast but use all the data to choose the trend? It would make more sense to weight the more recent trends more heavily.
4.3.5 Exponential smoothing model with trend
The exponential smoothing model with trend does this. The one-year trend is \[x_t - x_{t-1}\] That is how much the data increased or decreased.
plot(diff(anchovy87ts),ylim=c(-0.3,.3))
abline(h=0, col="blue")
abline(h=mean(diff(anchovy87ts)),col="red")
title("0 means no change")
If we take the average of all \(x_t - x_{t-1}\) we are using the average trend like the naive model with drift. We put an equal weighting on all trends.
But we could use a weighting that falls off exponentially so that we more recent trends affect the forecast more than trends in the distant past. That is what an exponential smoothing model with trend does.
4.3.6 Naive model with trend
If your training data are length \(T\), then a forecast for \(T+h\) is
\[\hat{x}_{T+h} = l_T + h \bar{b}\]
where \(\hat{b}\) is the mean of the the yearly changes in \(x\), so the mean of \(x_t - x_{t-1}\).
\[\hat{b} = \sum_{t=2}^T (x_t - x_{t-1})\]
4.3.7 Exponential smoothing model with trend
\[\hat{x}_{T+h} = l_T + h b_T\]
where \(b_T\) is a weighted average with the more recent trends given more weight.
\[b_t = \sum_{t=2}^T \beta (1-\beta)^{t-2}(x_t - x_{t-1})\]
Fit exponential smoothing with trend
fit <- forecast::ets(anchovy87ts, model="AAN")
fr <- forecast::forecast(fit, h=5)
plot(fr)
4.3.8 Decomposing your model fit
Sometimes you would like to see the smoothed level and smoothed trend that the model estimated. You can see that with plot(fit)
or autoplot(fit)
.
autoplot(fit)
4.3.9 Forecast performance
We can evaluate the forecast performance with forecasts of our test data or we can use all the data and use time-series cross-validation.
Let’s start with the former.
4.3.10 Test forecast performance
Test against a test data set
We will fit an an exponential smoothing model with trend to the training data and make a forecast for the years that we ‘held out’.
fit1 <- forecast::ets(traindat, model="AAN")
h=length(testdat)
fr <- forecast::forecast(fit1, h=h)
plot(fr)
points(length(traindat)+1:h, testdat, pch=2, col="red")
legend("topleft", c("forecast","actual"), pch=c(20,2), col=c("blue","red"))
We can calculate a variety of forecast error metrics with
forecast::accuracy(fr, testdat)
## ME RMSE MAE MPE MAPE MASE
## Training set 0.0155561 0.1788989 0.1442712 0.1272938 1.600532 0.7720807
## Test set -0.5001701 0.5384355 0.5001701 -5.1678506 5.167851 2.6767060
## ACF1
## Training set -0.008371542
## Test set NA
We would now repeat this for all the models in our candidate set and choose the model with the best forecast performance.
Test using time-series cross-validation
Another approach is to use all the data and test a series of forecasts made by fitting the model to different lengths of the data.
In this approach, we don’t have test data. Instead we will use all the data for fitting and for forecast testing.
We will redefine traindat
as all our Anchovy data.
tsCV() function
We will use the tsCV()
function. We need to define a function that returns a forecast.
far2 <- function(x, h, model){
fit <- ets(x, model=model)
forecast(fit, h=h)
}
Now we can use tsCV()
to run our far2()
function to a series of training data sets. We will specify that a NEW ets model be estimated for each training set. We are not using the weighting estimated for the whole data set but estimating the weighting new for each set.
The e
are our forecast errors for all the forecasts that we did with the data.
e <- forecast::tsCV(traindat, far2, h=1, model="AAN")
e
## Time Series:
## Start = 1
## End = 26
## Frequency = 1
## [1] -0.245378390 0.366852341 0.419678595 -0.414861770 -0.152727933
## [6] -0.183775208 -0.013799590 0.308433377 -0.017680471 -0.329690537
## [11] -0.353441463 0.266143346 -0.110848616 -0.005227309 0.157821831
## [16] 0.196184446 0.008135667 0.326024067 0.085160559 0.312668447
## [21] 0.246437781 0.117274740 0.292601670 -0.300814605 -0.406118961
## [26] NA
Let’s look at the first few e
so we see exactly with tsCV()
is doing.
e[2]
## [1] 0.3668523
This uses training data from \(t=1\) to \(t=2\) so fits an ets to the first two data points alone. Then it creates a forecast for \(t=3\) and compares that forecast to the actual value observed for \(t=3\).
TT <- 2 # end of the temp training data
temp <- traindat[1:TT]
fit.temp <- forecast::ets(temp, model="AAN")
fr.temp <- forecast::forecast(fit.temp, h=1)
traindat[TT+1] - fr.temp$mean
## Time Series:
## Start = 3
## End = 3
## Frequency = 1
## [1] 0.3668523
e[3]
## [1] 0.4196786
This uses training data from \(t=1\) to \(t=2\) so fits an ets to the first two data points alone. Then it creates a forecast for \(t=3\) and compares that forecast to the actual value observed for \(t=3\).
TT <- 3 # end of the temp training data
temp <- traindat[1:TT]
fit.temp <- forecast::ets(temp, model="AAN")
fr.temp <- forecast::forecast(fit.temp, h=1)
traindat[TT+1] - fr.temp$mean
## Time Series:
## Start = 4
## End = 4
## Frequency = 1
## [1] 0.4196786
4.3.11 Testing a specific ets model
By specifying model="AAN"
, we estimated a new ets model (meaning new weighting) for each training set used. We might want to specify that we use only the weighting we estimated for the full data set.
We do this by passing in a fit to model
.
The e
are our forecast errors for all the forecasts that we did with the data. fit1
below is the ets estimated from all the data 1964 to 1989. Note, the code will produce a warning that it is estimating the initial value and just using the weighting. That is what we want.
fit1 <- forecast::ets(traindat, model="AAN")
e <- forecast::tsCV(traindat, far2, h=1, model=fit1)
e
## Time Series:
## Start = 1
## End = 26
## Frequency = 1
## [1] NA 0.576663901 1.031385937 0.897828249 1.033164616
## [6] 0.935274283 0.958914499 1.265427119 -0.017241938 -0.332751184
## [11] -0.330473144 0.255886314 -0.103926617 0.031206730 0.154727479
## [16] 0.198328366 -0.020605522 0.297475742 0.005297401 0.264939892
## [21] 0.196256334 0.129798648 0.335887872 -0.074017535 -0.373267163
## [26] NA
4.3.12 Forecast accuracy metrics
Now we can compute forecast accuracy metrics from the forecast errors (e
).
RMSE: root mean squared error
rmse <- sqrt(mean(e^2, na.rm=TRUE))
MAE: mean absolute error
mae <- mean(abs(e), na.rm=TRUE)