```{r setup, include=FALSE, message=FALSE}
options(htmltools.dir.version = FALSE, servr.daemon = TRUE)
knitr::opts_chunk$set(fig.height=5, fig.align="center")
library(huxtable)
load("landings.RData")
greeklandings <- landings
```

layout: true

---

class: center, middle, inverse
# Forecasting Time Series
## Simple Exponential Smoothing

.futnote[Eli Holmes, UW SAFS]

.citation[eeholmes@uw.edu]

---

## Naive forecast

For a naive forecast of the anchovy catch in 1988, we just use the 1987 catch.

$$\hat{x}_{1988} = x_{1987}$$
Which is the same as saying that we put 100% of the 'weight' on the most recent value and no weight on any value prior to that.

$$\hat{x}_{1988} = 1 \times x_{1987} + 0 \times x_{1986} + 0 \times x_{1985} + \dots$$
---

Past values in the time series have information about the current state, but only the most recent past value.

```{r echo=FALSE}
plot(1987:1964, c(1,rep(0,23)), lwd=2, ylab="weight", xlab="", type="l")
title("weight put on past values for 1988 forecast")
```


---

That's a bit extreme.  Often the values prior to the last value also have some information about future states.  But the 'information content' should decrease the farther in the past that we go.

```{r echo=FALSE}
alpha <- 0.8
plot(1987:1964, alpha^(1:24), lwd=2, ylab="weight", xlab="", type="l")
title("more weight put on more recent values\nfor 1988 forecast")
```

---

Simple exponential smoothing uses this type of weighting that falls off exponentially and the objective to estimate the best weighting ( $\alpha$ ):

```{r echo=FALSE}
alpha <- 1
wts <- alpha*(1-alpha)^(0:23)
plot(1987:1964, wts/sum(wts), lwd=2, ylab="weight", xlab="", type="l")
alpha <- 0.5
wts <- alpha*(1-alpha)^(0:23)
lines(1987:1964, wts/sum(wts), lwd=2, col="blue")
alpha <- 0.05
wts <- alpha*(1-alpha)^(0:23)
lines(1987:1964, wts/sum(wts), lwd=2, col="red")
legend("topleft", c("alpha=1 like naive","alpha=0.5","alpha=0.05 like mean"),lwd=2, col=c("black","blue","red"))
title("more weight put on more recent values\nfor 1988 forecast")
```

---

## Fitting exponential smoothing models

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.
    * Z=choose, A=additive, M=muplicative
    * first letter is for level 
    * second letter is for trend
    * third letter is for season

---

We are going to `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'.

---

## Fit 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.

```{r load_data_exp_smoothing}
data(greeklandings, package="FishForecast")
anchovy <- subset(greeklandings, 
                  Species=="Anchovy" & Year<=1987)$log.metric.tons
anchovy <- ts(anchovy, start=1964)
library(forecast)
```

```{r fit.ann}
fit <- ets(anchovy, model="ANN")
fr <- forecast(fit, h=5)
```

---

```{r}
plot(fr)
```

---

## Look at the estimates

```{r}
fit
```

---

## The weighting function

```{r ann.weighting, echo=FALSE}
alpha <- coef(fit)[1]
wts <- alpha*(1-alpha)^(0:23)
plot(1987:1964, wts/sum(wts), lwd=2, ylab="weight", xlab="", type="l")
title("Weighting for simple exp. smooth of anchovy")
```

---

## Produce forecast with ets from 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:

```{r}
fit1 <- ets(anchovy, model="ANN")
```

Use that model with the 2000-2007 data and produce a forecast:

```{r fit.new.ann}
dat <- subset(landings, Species=="Anchovy" & Year>=2000 & Year<=2007)
dat <- ts(dat$log.metric.tons, start=2000)
fit2 <- ets(dat, model=fit1)
fr2 <- forecast(fit2, h=5)
```

---

```{r}
plot(fr2)
```

---

## 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.

```{r fig.height=4.5}
fit.rwf <- Arima(anchovy, order=c(0,1,0), include.drift=TRUE)
fr.rwf <- 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.

```{r}
coef(fit.rwf)
```

The trend from all the data is (last-first)/(number of steps).

```{r}
mean(diff(anchovy))
```

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.

---

## 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.  

---

```{r}
plot(diff(anchovy),ylim=c(-0.3,.3))
abline(h=0, col="blue")
abline(h=mean(diff(anchovy)),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.

```{r echo=FALSE}
alpha <- 1
wts <- alpha*(1-alpha)^(0:23)
plot(1987:1964, wts/sum(wts), lwd=2, ylab="weight", xlab="", type="l")
alpha <- 0.5
wts <- alpha*(1-alpha)^(0:23)
lines(1987:1964, wts/sum(wts), lwd=2, col="blue")
alpha <- 0.05
wts <- alpha*(1-alpha)^(0:23)
lines(1987:1964, wts/sum(wts), lwd=2, col="red")
legend("topleft", c("beta=1","beta=0.5","beta=0.05 like rw with drift"),lwd=2, col=c("black","blue","red"), bty="n")
title("more weight put on more recent values\nfor 1988 forecast")
```

---

## 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})$$

## 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

```{r}
fit <- ets(anchovy, model="AAN")
fr <- forecast(fit, h=5)
plot(fr)
```

---

## 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)`.

```{r fig.height=4}
autoplot(fit)
```

---

## Validation

---

```{r load_packages, echo=FALSE, message=FALSE, warning=FALSE}
library(ggplot2)
library(gridExtra)
library(reshape2)
library(tseries)
library(forecast)
```

```{r load_data2, message=FALSE, warning=FALSE, echo=FALSE}
load("landings.RData")
```

## Measures of forecast fit

To measure the forecast fit, we fit a model to training data and test a forecast against data in a test set.  We 'held out' the test data and did not use it at all in our fitting.

```{r echo=FALSE}
spp <- "Anchovy"
training = subset(landings, Year <= 1987)
test = subset(landings, Year >= 1988 & Year <= 1989)

traindat <- subset(training, Species==spp)$log.metric.tons
testdat <- subset(test, Species==spp)$log.metric.tons
plot(1964:1987, traindat, xlim=c(1964,1989))
points(1988:1989, testdat, pch=2, col="red")
legend("topleft", c("Training data","Test data"), pch=c(1,2), col=c("black", "red"))
```

---

We will fit to the training data and make a forecast.

```{r}
fit1 <- auto.arima(traindat)
fr <- forecast(fit1, h=2)
fr
```

```{r echo=FALSE}
plot(fr)
points(25:26, testdat, pch=2, col="red")
legend("topleft", c("forecast","actual"), pch=c(20,2), col=c("blue","red"))
```

---

How to we quantify the difference between the forecast and the actual values?

```{r}
fr.err <- testdat - fr$mean
fr.err
```

There are many metrics.  The `accuracy()` function in forecast provides many different metrics: mean error, root mean square error, mean absolute error, mean percentage error, mean absolute percentage error.

---

### ME Mean err

```{r}
me <- mean(fr.err)
me
```

### RMSE Root mean squared error

```{r}
rmse <- sqrt(mean(fr.err^2))
rmse
```

### MAE Mean absolute error

```{r}
mae <- mean(abs(fr.err))
mae
```

---

### MPE Mean percentage error

```{r}
fr.pe <- 100*fr.err/testdat
mpe <- mean(fr.pe)
mpe
```

### MAPE Mean absolute percentage error

```{r}
mape <- mean(abs(fr.pe))
mape
```

---

```{r}
accuracy(fr, testdat)[,1:5]
```

```{r}
c(me, rmse, mae, mpe, mape)
```

---

## Test all the models in your candidate model

Now that you have some metrics for forecast accuracy, you can compute these for all the models in your candidate set.

```{r}
# The model picked by auto.arima
fit1 <- Arima(traindat, order=c(0,1,1))
fr1 <- forecast(fit1, h=2)
test1 <- accuracy(fr1, testdat)[2,1:5]

# AR-1
fit2 <- Arima(traindat, order=c(1,1,0))
fr2 <- forecast(fit2, h=2)
test2 <- accuracy(fr2, testdat)[2,1:5]

# Naive model with drift
fit3 <- rwf(traindat, drift=TRUE)
fr3 <- forecast(fit3, h=2)
test3 <- accuracy(fr3, testdat)[2,1:5]
```

---

## Show a summary

```{r results='asis', echo=FALSE}
sum.tests <- rbind(test1, test2, test3)
row.names(sum.tests) <- c("(0,1,1)","(1,1,0)","Naive")
sum.tests <- format(sum.tests, digits=3)
knitr::kable(sum.tests, format="html")
```

---

## Cross-Validation

An alternate approach to testing a model's forecast accuracy is to use windows or shorter segments of the whole time series to make a series of single forecasts.  

```{r cv.sliding, echo=FALSE}
p <- list()
for(i in 1:9){
  p[[i]]<-ggplot(subset(landings, Species=="Anchovy"&Year<1974+i), aes(x=Year, y=log.metric.tons))+geom_point()+ylab("landings")+xlab("")+xlim(1964,1990)+ylim(8,12)+
    geom_point(data=subset(landings, Species=="Anchovy"&Year==1974+i),aes(x=Year,y=log.metric.tons),color="red") +
    ggtitle(paste0("forecast ",i))
}
gridExtra::grid.arrange(
  p[[1]],p[[2]],p[[3]],p[[4]],p[[5]],p[[6]],p[[7]],p[[8]],p[[9]],nrow=3,
  top = grid::textGrob("Cross-validation: sliding window", gp=grid::gpar(fontsize=20,font=3))
)
```

---

Another approach uses a fixed window.  For example, a 10-year window.

```{r cv.fixed, echo=FALSE}
p <- list()
for(i in 1:9){
  p[[i]]<-ggplot(subset(landings, Species=="Anchovy"&Year>=1964+i-1&Year<1974+i), aes(x=Year, y=log.metric.tons))+geom_point()+ylab("landings")+xlab("")+xlim(1964,1990)+ylim(8,12)+
    geom_point(data=subset(landings, Species=="Anchovy"&Year==1974+i),aes(x=Year,y=log.metric.tons),color="red") +
    ggtitle(paste0("forecast ",i))
}
gridExtra::grid.arrange(
  p[[1]],p[[2]],p[[3]],p[[4]],p[[5]],p[[6]],p[[7]],p[[8]],p[[9]],nrow=3,
  top = grid::textGrob("Cross-validation: fixed window", gp=grid::gpar(fontsize=20,font=3))
)
```

---

## Time-series cross-validation with the forecast package

```{r}
far2 <- function(x, h, order){
  forecast(Arima(x, order=order), h=h)
  }
e <- tsCV(traindat, far2, h=1, order=c(0,1,1))
tscv1 <- c(ME=mean(e, na.rm=TRUE), RMSE=sqrt(mean(e^2, na.rm=TRUE)), MAE=mean(abs(e), na.rm=TRUE))
tscv1
```

Compare to RMSE from just the 2 test data points.
```{r}
test1[c("ME","RMSE","MAE")]
```

---

## Cross-validation farther in future

```{r cv.sliding.4plot, echo=FALSE}
p <- list()
for(i in 1:9){
  p[[i]]<-ggplot(subset(landings, Species=="Anchovy"&Year<1974+i), aes(x=Year, y=log.metric.tons))+geom_point()+ylab("landings")+xlab("")+xlim(1964,1990)+ylim(8,12)+
    geom_point(data=subset(landings, Species=="Anchovy"&Year==1974+i+3),aes(x=Year,y=log.metric.tons),color="red") +
    ggtitle(paste0("forecast ",i))
}
gridExtra::grid.arrange(
  p[[1]],p[[2]],p[[3]],p[[4]],p[[5]],p[[6]],p[[7]],p[[8]],p[[9]],nrow=3,
  top = grid::textGrob("Cross-validation: 4 step ahead forecast", gp=grid::gpar(fontsize=20,font=3))
)
```


---

Compare accuracy of forecasts 1 year out versus 4 years out.  If `h` is greater than 1, then the errors are returned as a matrix with each `h` in a column.  Column 4 is the forecast, 4 years out.

```{r cv.sliding.4}
e <- tsCV(traindat, far2, h=4, order=c(0,1,1))[,4]
#RMSE
tscv4 <- c(ME=mean(e, na.rm=TRUE), RMSE=sqrt(mean(e^2, na.rm=TRUE)), MAE=mean(abs(e), na.rm=TRUE))
rbind(tscv1, tscv4)
```

---

Compare accuracy of forecasts with a fixed 10-year window and 1-year out forecasts.

```{r fixed.cv.1}
e <- tsCV(traindat, far2, h=1, order=c(0,1,1), window=10)
#RMSE
tscvf1 <- c(ME=mean(e, na.rm=TRUE), RMSE=sqrt(mean(e^2, na.rm=TRUE)), MAE=mean(abs(e), na.rm=TRUE))
tscvf1
```

---

```{r results='asis'}
comp.tab <- rbind(test1=test1[c("ME","RMSE","MAE")],
      slide1=tscv1,
      slide4=tscv4,
      fixed1=tscvf1)
knitr::kable(comp.tab, format="html")
```


---

## Forecast performance for ETS models

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.

```{r echo=FALSE}
spp <- "Anchovy"
training = subset(greeklandings, Year <= 1987)
test = subset(greeklandings, Year >= 1988 & Year <= 1989)

traindat <- ts(subset(training, Species==spp)$log.metric.tons, start=1964)
testdat <- ts(subset(test, Species==spp)$log.metric.tons, start=1988)
```

---

## Test forecast performance 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'. 

```{r fig.height=4, echo=FALSE}
fit1 <- ets(traindat, model="AAN")
h=length(testdat)
fr <- forecast(fit1, h=h)
plot(fr)
points(end(traindat)[1]+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

```{r}
accuracy(fr, testdat)
```

We would now repeat this for all the models in our candidate set and choose the model with the best forecast performance.

---

## Forecast performance with time-series cross-validation

We can use `tsCV()` as we did for ARIMA models.  We will redefine `traindat` as all our Anchovy data.

```{r subset.anch, echo=FALSE}
spp <- "Anchovy"
training = subset(landings, Year <= 1989)
traindat <- subset(training, Species==spp)$log.metric.tons
```

---

## tsCV() function

We will use the `tsCV()` function.  We need to define a function that returns a forecast.

```{r def.far2}
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.

```{r}
e <- tsCV(traindat, far2, h=1, model="AAN")
e
```

---

Let's look at the first few `e` so we see exactly with `tsCV()` is doing.

```{r}
e[2]
```

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$.

```{r}
TT <- 2 # end of the temp training data
temp <- traindat[1:TT]
fit.temp <- ets(temp, model="AAN")
fr.temp <- forecast(fit.temp, h=1)
traindat[TT+1] - fr.temp$mean
```

---

```{r}
e[3]
```

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$.

```{r}
TT <- 3 # end of the temp training data
temp <- traindat[1:TT]
fit.temp <- ets(temp, model="AAN")
fr.temp <- forecast(fit.temp, h=1)
traindat[TT+1] - fr.temp$mean
```

---

## 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.

```{r, message=FALSE, warning=FALSE}
fit1 <- ets(traindat, model="AAN")
e <- tsCV(traindat, far2, h=1, model=fit1)
e
```

---

## Forecast accuracy metrics

Now we can compute forecast accuracy metrics from the forecast errors (`e`).

RMSE: root mean squared error
```{r rmse}
rmse <- sqrt(mean(e^2, na.rm=TRUE))
```

MAE: mean absolute error
```{r mae}
mae <- mean(abs(e), na.rm=TRUE)
```

We would repeat this process for all models in our candidate set and compare forecast fits to choose our forecast model.

---

## Comparing performance in a candidate set

Now you are ready to compare forecasts from a variety of models and choose a forecast model.  Note when you compare models, you can use both 'training data/test data' and use time-series cross-validation, but report the metrics in separate columns.  Example, 'RMSE from tsCV' and 'RMSE from test data'.

---

## Example candidate set for anchovy

* Exponential smoothing model with trend
```
fit <- ets(traindat, model="AAN")
fr <- forecast(fit, h=1)
```
* Exponential smoothing model no trend
```
fit <- ets(traindat, model="ANN")
fr <- forecast(fit, h=1)
```
* ARIMA(0,1,1) with drift (best)
```
fit <- Arima(traindat, order(0,1,1), include.drift=TRUE)
fr <- forecast(fit, h=1)
```
* ARIMA(2,1,0) with drift (within 2 AIC of best)
```
fit <- Arima(traindat, order(2,1,0), include.drift=TRUE)
fr <- forecast(fr)
```

---

## Candidata models continued

* Time-varying regression with linear time
```
traindat$t <- 1:24
fit <- lm(log.metric.tons ~ t, data=traindat)
fr <- forecast(fit, newdata=data.frame(t=25))
```

* Naive no trend
```
fit <- Arima(traindat, order(0,1,0))
fr <- forecast(fit, h=1)
# or simply
fr <- rwf(traindat)
```
* Naive with trend
```
fit <- Arima(traindat, order(0,1,0), include.drift=TRUE)
fr <- forecast(fit)
# or simply
fr <- rwf(traindat, drift=TRUE)
```
* Average or mean
```
fit <- Arima(traindat, order(0,0,0))
fr <- forecast(fit)
```

---

## Seasonal Exponential Smoothing Models

```{r}
load("chinook.RData")
head(chinook)
```

---

The data are monthly and start in January 1990.  To make this into a ts object do

```{r}
chinookts <- ts(chinook$log.metric.tons, start=c(1990,1), frequency=12)
```
`start` is the year and month and frequency is the number of months in the year.  

---

## Plot seasonal data

Now that we have specified our seasonal data as a ts object, it is easy to plot because R knows what the season is.

```{r}
plot(chinookts)
```

---

## Seasonal Exponential Smoothing Model

Now we add a few more lines to our ETS table of models:

model  | "ZZZ" | alternate function |
------------- | ------------- | --------- |
exponential smoothing no trend | "ANN" | `ses()` |
exponential smoothing with trend  | "AAN" | `holt()` |
exponential smoothing with season no trend  | "ANA" | NA |
exponential smoothing with season and trend  | "AAA" | NA |
estimate best trend and season model | "ZZZ" | NA |

Unfortunately `ets()` will not handle missing values and will find the longest continuous piece of our data and use that.

---


```{r}
library(forecast)
traindat <- window(chinookts, c(1990,1), c(1999,12))
fit <- ets(traindat, model="AAA")
fr <- forecast(fit, h=24)
plot(fr)
points(window(chinookts, c(1996,1), c(1996,12)))
```

---

## Decompose

If we plot the decomposition, we see the the seasonal component is not changing over time, unlike the actual data.  The bar on the right, alerts us that the scale on the 3rd panel is much smaller.

```{r fig.height=4}
autoplot(fit)
```

---

## Force seasonality to evolve more

Pass in a high `gamma` (the season weighting) to force the seasonality to evolve.
```{r fig.height=4}
fit <- ets(traindat, model="AAA", gamma=0.4)
autoplot(fit)
```

---

## Compare to a seasonal ARIMA model

`auto.arima()` will recognize that our data has season and fit a seasonal ARIMA model to our data.  Let's use the data that `ets()` used.  This is shorter than our training data.  The data used by `ets()` is returned in `fit$x`.

---

```{r}
no_miss_dat <- fit$x
fit <- auto.arima(no_miss_dat)
fr <- forecast(fit, h=12)
plot(fr)
points(window(chinookts, c(1996,1), c(1996,12)))
```

---

## Missing values are ok when fitting a seasonal ARIMA model

```{r}
fit <- auto.arima(traindat)
fr <- forecast(fit, h=12)
plot(fr)
```

---

## Forecast evaluation

We can compute the forecast performance metrics as usual. 

```{r}
fit <- ets(traindat, model="AAA", gamma=0.4)
fr <- forecast(fit, h=12)
```
Look at the forecast so you know what years and months to include in your test data.  Pull those 12 months out of your data using the `window()` function.

```{r}
testdat <- window(traindat, c(1996,1), c(1996,12))
```
Use `accuracy()` to get the forecast error metrics.
```{r}
accuracy(fr, testdat)
```

---

We can do the same for the ARIMA model.

```{r}
no_miss_dat <- fit$x
fit <- auto.arima(no_miss_dat)
fr <- forecast(fit, h=12)
accuracy(fr, testdat)
```

---

## Lab on Thursday

Comparing candidates sets of models.

