Second Order Exponential Smoothing in R

07.30.2021

Intro

Second Order Exponential Smoothing extends Simple Exponential Smoothing by adding a Trend Smoother. If SES doesn’t work well, we can see if there is a trend and add another component to our model to account for that. In this article, we will learn how to conduct Second Order Exponential Smoothing in R.

Data

Let’s load a data set of monthly milk production. We will load it from the url below. The data consists of monthly intervals and kilograms of milk produced.

df <- read.csv('https://raw.githubusercontent.com/ourcodingclub/CC-time-series/master/monthly_milk.csv')
df$month = as.Date(df$month)
head(df)
##        month milk_prod_per_cow_kg
## 1 1962-01-01               265.05
## 2 1962-02-01               252.45
## 3 1962-03-01               288.00
## 4 1962-04-01               295.20
## 5 1962-05-01               327.15
## 6 1962-06-01               313.65

Now, we convert our data to a time series object using the R ts method.

df.ts = ts(df[, -1], frequency = 12, start=c(1962, 1, 1))
head(df.ts)
## [1] 265.05 252.45 288.00 295.20 327.15 313.65

Second Order Exponential Smoothing in R"

Let’s start by plotting our time series.

plot(df.ts)

unnamed chunk 3 1

To create a second order exponential smoothing model, we can use the holt method from the fpp2 package. Here we can pass our time series, specify a beta value (our trend smoothing parameter), and specify a horizon h, how many months out (since our data is monthly).

library(fpp2) 
## Registered S3 method overwritten by 'quantmod':
##   method            from
##   as.zoo.data.frame zoo

## -- Attaching packages ---------------------------------------------- fpp2 2.4 --

## v ggplot2   3.3.5     v fma       2.4  
## v forecast  8.15      v expsmooth 2.3

## 
ses.ts <- holt(
  df.ts,
  beta = .4,
  h = 100
)
autoplot(ses.ts)

unnamed chunk 4 1

Second Order Exponential Smothing By Hand

Second order exponential smoothing builds on SES by adding a trend component. If you worked through the ses example, you will be able to solve second order with a sligh modificiation.

The equation for SES is the following: Fi + 1 = α**yi + (1 − α)(Fi − Tt − 1)

Where T_t is the trend smothing component defined as follows:

Tt + 1 = β(Ft − Ft − 1) + (1 − β)Tt − 1

Then, we get the predicted value by:

t + 1 = Ft + Tt

Whe initialize the algorithm as follows

y^1=y1y^2=y^1+T1\hat{y}_{1} = y_1 \\ \hat{y}_{2} = \hat{y}_1 + T_1

To initialize the first trend, we have multiple options. Here are two common ways:

Tt=y2y1Tt=(yny1)/(n1)T_t = y_2 - y_1 \\ T_t = (y_n - y_1)/(n-1) \\

Now, we move to an example. Let’s say we have the following data.

t y
1 3
2 5
3 9
4 20

We can apply our model as follows. We will use an alpha of .4 and beta of .3.

For t = 1.

F1=y1=3T1=y2y1=53=2haty1=y1=3F_{1} = y_1 = 3 \\ T_1 = y_2 - y_1 = 5 - 3 = 2 \\ \\hat{y}_1 = y_1 = 3

Now for t = 2.

F2=αy1+(1α)(F1+T1)=.43+(1.4)(3+2)=4.2F_{2} = \alpha y_1 + (1- \alpha)(F_1 + T_1) \\ = .4 *3 + (1 - .4) * (3 + 2) \\ = 4.2
T2=β(F2F1)+(1β)T1=.3(4.23)+(1.3)2=1.76T_2 = \beta(F_2 - F_1) + (1 - \beta)T_1 \\ = .3 (4.2 - 3) + (1 - .3) * 2 \\ = 1.76

2 = F2 + T2 = 4.2 + 1.76 = 5.96

For t = 3

F3=αy2+(1α)(F2+T2)=.45+(1.4)(4.2+1.76)=5.576F_{3} = \alpha y_2 + (1- \alpha)(F_2 + T_2) \\ = .4 * 5 + (1 - .4) * (4.2 + 1.76) \\ = 5.576
T3=β(F3F2)+(1β)T2=.3(5.5764.2)+(1.3)1.76=1.6448T_3 = \beta(F_3 - F_2) + (1 - \beta)T_2 \\ = .3 (5.576 - 4.2) + (1 - .3) * 1.76 \\ = 1.6448

2 = F2 + T2 = 5.576 + 1.6448 = 7.2208

For t = 4

F4=αy3+(1α)(F3+T3)=.49+(1.4)(5.576+1.6448)=7.93248F_4 = \alpha y_3 + (1- \alpha)(F_3 + T_3) \\ = .4 * 9 + (1 - .4) * (5.576 + 1.6448) \\ = 7.93248
T4=β(F4F3)+(1β)T3=.3(7.932485.576)+(1.3)1.6448=1.858304T_4 = \beta(F_4 - F_3) + (1 - \beta)T_3 \\ = .3 (7.93248 - 5.576) + (1 - .3) * 1.6448 \\ = 1.858304

2 = F2 + T2 = 7.93248 + 1.858304 = 9.790784 Let’s finish by writing some simple code to replicate this.

y = c(3, 5, 9, 20)

## Start with the first point
forcast = c(y[1])
alpha = .4
beta = .3

# Initialize
F = y[1]
trend = y[2] - y[1]

for (i in 2:length(y)) {
    prev_F = F
    F = alpha * y[i - 1] + (1 - alpha) * (F + trend)
    trend = beta * (F - prev_F) + (1 - beta) * trend
    forcast = append(forcast, F + trend)
}
    

forcast
## [1] 3.000000 5.960000 7.220800 9.790784