library(fpp2)
## Warning: package 'fpp2' was built under R version 4.0.5
## 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
## Warning: package 'ggplot2' was built under R version 4.0.5
## Warning: package 'forecast' was built under R version 4.0.5
## Warning: package 'fma' was built under R version 4.0.5
## Warning: package 'expsmooth' was built under R version 4.0.5
##
library(forecast)
library(tidyverse)
## Warning: package 'tidyverse' was built under R version 4.0.5
## -- Attaching packages --------------------------------------- tidyverse 1.3.1 --
## v tibble 3.1.6 v dplyr 1.0.7
## v tidyr 1.1.4 v stringr 1.4.0
## v readr 2.1.0 v forcats 0.5.1
## v purrr 0.3.4
## Warning: package 'tibble' was built under R version 4.0.5
## Warning: package 'tidyr' was built under R version 4.0.5
## Warning: package 'readr' was built under R version 4.0.5
## Warning: package 'purrr' was built under R version 4.0.5
## Warning: package 'dplyr' was built under R version 4.0.5
## Warning: package 'stringr' was built under R version 4.0.5
## Warning: package 'forcats' was built under R version 4.0.5
## -- Conflicts ------------------------------------------ tidyverse_conflicts() --
## x dplyr::filter() masks stats::filter()
## x dplyr::lag() masks stats::lag()
library(tseries)
## Warning: package 'tseries' was built under R version 4.0.5
library(Quandl)
## Warning: package 'Quandl' was built under R version 4.0.5
## Loading required package: xts
## Warning: package 'xts' was built under R version 4.0.5
## Loading required package: zoo
## Warning: package 'zoo' was built under R version 4.0.5
##
## Attaching package: 'zoo'
## The following objects are masked from 'package:base':
##
## as.Date, as.Date.numeric
##
## Attaching package: 'xts'
## The following objects are masked from 'package:dplyr':
##
## first, last
pigs <- fma::pigs
tsdisplay(pigs)
plot(pigs)
sespigs = ses(pigs, h=4)
sespigs$model
## Simple exponential smoothing
##
## Call:
## ses(y = pigs, h = 4)
##
## Smoothing parameters:
## alpha = 0.2971
##
## Initial states:
## l = 77260.0561
##
## sigma: 10308.58
##
## AIC AICc BIC
## 4462.955 4463.086 4472.665
autoplot(sespigs)
sespigs$upper[1, "95%"]
## 95%
## 119020.8
sespigs$lower[1, "95%"]
## 95%
## 78611.97
s = sd(sespigs$residuals)
sespigs$mean[1] + 1.96*s
## [1] 118952.8
sespigs$mean[1] - 1.96*s
## [1] 78679.97
#q2
SES <- function(y, alpha, l0){
y_hat <- l0
for(index in 1:length(y)){
y_hat <- alpha*y[index] + (1 - alpha)*y_hat
}
cat("Next Observation of SES",
as.character(y_hat),
sep = "\n")
}
alpha <- sespigs$model$par[1]
l0 <- sespigs$model$par[2]
SES(pigs, alpha = alpha, l0 = l0)
## Next Observation of SES
## 98816.4061115907
writeLines(paste(
"Next observation of SES", as.character(sespigs$mean[1])
))
## Next observation of SES 98816.4061115907
sespigs = ses(pigs, h=4)
sespigs
## Point Forecast Lo 80 Hi 80 Lo 95 Hi 95
## Sep 1995 98816.41 85605.43 112027.4 78611.97 119020.8
## Oct 1995 98816.41 85034.52 112598.3 77738.83 119894.0
## Nov 1995 98816.41 84486.34 113146.5 76900.46 120732.4
## Dec 1995 98816.41 83958.37 113674.4 76092.99 121539.8
The point observation is the same from SES function and my own function
#Q3
SES <- function(pars = c(alpha, l0), y){
error <- 0
SSE <- 0
alpha <- pars[1]
l0 <- pars[2]
y_hat <- l0
for(index in 1:length(y)){
error <- y[index] - y_hat
SSE <- SSE + error^2
y_hat <- alpha*y[index] + (1 - alpha)*y_hat
}
return(SSE)
}
# compare ses and SES using pigs data
opt_SES_pigs <- optim(par = c(0.5, pigs[1]), y = pigs, fn = SES)
writeLines(paste(
"Optimal parameters",
"\n",
as.character(opt_SES_pigs$par[1]),
", ",
as.character(opt_SES_pigs$par[2]),
sep = ""
))
## Optimal parameters
## 0.299008094014243, 76379.2653476235
writeLines(paste(
"Parameters",
"\n",
as.character(sespigs$model$par[1]),
", ",
as.character(sespigs$model$par[2]),
sep = ""))
## Parameters
## 0.297148833372095, 77260.0561458528
The alpha value is a little larger using the optimal ses function and the the los were close as well.
#Q4
SES <- function(init_pars, data){
fc_next <- 0
SSE <- function(pars, data){
error <- 0
SSE <- 0
alpha <- pars[1]
l0 <- pars[2]
y_hat <- l0
for(index in 1:length(data)){
error <- data[index] - y_hat
SSE <- SSE + error^2
y_hat <- alpha*data[index] + (1 - alpha)*y_hat
}
fc_next <<- y_hat
return(SSE)
}
.
optim_pars <- optim(par = init_pars, data = data, fn = SSE)
return(list(
Next_observation_forecast = fc_next,
alpha = optim_pars$par[1],
l0 = optim_pars$par[2]
))
}
print("Next obsfc by ses")
## [1] "Next obsfc by ses"
sespigs$mean[1]
## [1] 98816.41
print("alpha by ses")
## [1] "alpha by ses"
sespigs$model$par[1]
## alpha
## 0.2971488
print("l0 by ses")
## [1] "l0 by ses"
sespigs$model$par[2]
## l
## 77260.06
#Q5
autoplot(books)
sespaper= ses(books[,"Paperback"], h=4)
seshard = ses(books[,"Hardcover"], h=4)
autoplot(sespaper)
autoplot(seshard)
spaper = sqrt(mean(sespaper$residuals^2))
shard = sqrt(mean(seshard$residuals^2))
#Q6
#6A
holtpaper = holt(books[,"Paperback"], h=4)
holthard = holt(books[,"Hardcover"], h=4)
#6B
hpaper = sqrt(mean(holtpaper$residuals^2))
hhard = sqrt(mean(holthard$residuals^2))
#6C
autoplot(holtpaper)
autoplot(sespaper)
autoplot(holthard)
autoplot(seshard)
#Holt’s method is better because it captures the upward trend better
#6D
holtpaper$upper[1, "95%"]
## 95%
## 275.0205
holtpaper$lower[1, "95%"]
## 95%
## 143.913
holtpaper$mean[1] +1.96*hpaper
## [1] 270.4951
holtpaper$mean[1] -1.96*hpaper
## [1] 148.4384
holthard$upper[1, "95%"]
## 95%
## 307.4256
holthard$lower[1, "95%"]
## 95%
## 192.9222
holthard$mean[1] + 1.96*hhard
## [1] 303.4733
holthard$mean[1] - 1.96*hhard
## [1] 196.8745
#7
## Time-Series [1:94] from 1900 to 1993: 277 315 315 321 315 ...
## Time Series:
## Start = 1900
## End = 1905
## Frequency = 1
## [1] 276.79 315.42 314.87 321.25 314.54 317.92
## RMSE when using holt function
## [1] 26.58219
## RMSE when using holt function with damped option
## [1] 26.54019
## RMSE when using holt function with Box-Cox transformation
## [1] 1.032217
## RMSE when using holt function with damped option and Box-Cox transformation
## [1] 1.039187
. The best model was the Box-Cox transformation with Holt’s linear method. It gave pint forecasts and prediction intervals witha damping effect. Holt’s method went into the negatiive the damped method keeps from going to 0 but doesnt follow the overal downward trend.
#8
## [1] 14.72762
## [1] 14.94306
##
## Ljung-Box test
##
## data: Residuals from Damped Holt-Winters' multiplicative method
## Q* = 42.932, df = 7, p-value = 3.437e-07
##
## Model df: 17. Total lags used: 24
## ME RMSE MAE MPE MAPE MASE
## Training set 0.4556121 8.681456 6.24903 0.2040939 3.151257 0.3916228
## Test set 94.7346169 111.911266 94.73462 24.2839784 24.283978 5.9369594
## ACF1 Theil's U
## Training set -0.01331859 NA
## Test set 0.60960299 1.90013
## ME RMSE MAE MPE MAPE MASE
## Training set 0.03021223 9.107356 6.553533 0.001995484 3.293399 0.4107058
## Test set 78.34068365 94.806617 78.340684 19.945024968 19.945025 4.9095618
## ACF1 Theil's U
## Training set 0.02752875 NA
## Test set 0.52802701 1.613903
#9
fc_stl_ets_retail_train <- ts_retail_train %>%
stlm(
s.window = 13,
robust = TRUE,
method = "ets",
lambda = BoxCox.lambda(ts_retail_train)
) %>%
forecast(
h = 36,
lambda = BoxCox.lambda(ts_retail_train)
)
## Warning in InvBoxCox(fcast$mean, lambda, biasadj, fcast): biasadj information
## not found, defaulting to FALSE.
autoplot(fc_stl_ets_retail_train)
accuracy(fc_stl_ets_retail_train, ts_retail_test)
## ME RMSE MAE MPE MAPE MASE
## Training set -0.6782982 8.583559 5.918078 -0.3254076 2.913104 0.3708823
## Test set 82.1015276 98.384220 82.101528 21.0189982 21.018998 5.1452516
## ACF1 Theil's U
## Training set 0.02704667 NA
## Test set 0.52161725 1.679783
fc_stl_ets_retail_train_without_tr <-
ts_retail_train %>%
stlm(
s.window = 13,
robust = TRUE,
method = "ets"
) %>%
forecast(h = 36)
autoplot(fc_stl_ets_retail_train_without_tr)
accuracy(fc_stl_ets_retail_train_without_tr,
ts_retail_test)
## ME RMSE MAE MPE MAPE MASE
## Training set -0.5020795 10.00826 6.851597 -0.391432 3.489759 0.4293853
## Test set 74.2529959 91.04491 74.252996 18.837766 18.837766 4.6533890
## ACF1 Theil's U
## Training set 0.09741266 NA
## Test set 0.48917501 1.549271
# I couldn't expect it because when I also used transformation, the accuracy of training set was better. In fact, the actual values in forecast horizon increased exponentially. Without using transformation, the forecast may reflect that bigger values have bigger variation. ETS forecasting after STL decomposition 'without' Box-Cox transformation yielded better result than when ETS(A, Ad, M) or ETS(A, A, M) was used.
#10
#10A
autoplot(ukcars)
#TThere is a downward trend until around 1982, then trends upwards until 2000, where it dips and then plateus.
#10B
stlcars = stl(ukcars, s.window=4, robust=TRUE)
autoplot(stlcars)
seas.stlcars = seasadj(stlcars)
autoplot(seas.stlcars)
#10C
add.damp.stl = stlf(seas.stlcars, etsmodel= "AAN", damped=TRUE, h=8)
autoplot(add.damp.stl)
#10D
holtfc = stlf(seas.stlcars, etsmodel="AAN", damped=FALSE, h=8)
autoplot(holtfc)
#10E
etsfc = ets(ukcars)
summary(etsfc)
## ETS(A,N,A)
##
## Call:
## ets(y = ukcars)
##
## Smoothing parameters:
## alpha = 0.6199
## gamma = 1e-04
##
## Initial states:
## l = 314.2568
## s = -1.7579 -44.9601 21.1956 25.5223
##
## sigma: 25.9302
##
## AIC AICc BIC
## 1277.752 1278.819 1296.844
##
## Training set error measures:
## ME RMSE MAE MPE MAPE MASE
## Training set 1.313884 25.23244 20.17907 -0.1570979 6.629003 0.6576259
## ACF1
## Training set 0.02573334
#10F
#Accuracy of additive damped trend method
accuracy(add.damp.stl)
## ME RMSE MAE MPE MAPE MASE
## Training set 1.854493 21.0918 16.59365 0.3029367 5.320469 0.5380042
## ACF1
## Training set -0.005454679
accuracy(holtfc)
## ME RMSE MAE MPE MAPE MASE
## Training set -0.354125 21.1403 16.47804 -0.4358911 5.319257 0.5342557
## ACF1
## Training set 0.004332171
accuracy(etsfc)
## ME RMSE MAE MPE MAPE MASE
## Training set 1.313884 25.23244 20.17907 -0.1570979 6.629003 0.6576259
## ACF1
## Training set 0.02573334
#10G
autoplot(add.damp.stl)
autoplot(holtfc)
autoplot(forecast(etsfc, h=8))
#2 are seasonally adjusted
#10H
checkresiduals(add.damp.stl)
## Warning in checkresiduals(add.damp.stl): The fitted degrees of freedom is based
## on the model used for the seasonally adjusted data.
##
## Ljung-Box test
##
## data: Residuals from STL + ETS(A,Ad,N)
## Q* = 48.348, df = 3, p-value = 1.796e-10
##
## Model df: 5. Total lags used: 8
checkresiduals(holtfc)
## Warning in checkresiduals(holtfc): The fitted degrees of freedom is based on the
## model used for the seasonally adjusted data.
##
## Ljung-Box test
##
## data: Residuals from STL + ETS(A,A,N)
## Q* = 45.837, df = 4, p-value = 2.663e-09
##
## Model df: 4. Total lags used: 8
checkresiduals(forecast(etsfc, h=8))
##
## Ljung-Box test
##
## data: Residuals from ETS(A,N,A)
## Q* = 18.324, df = 3, p-value = 0.0003772
##
## Model df: 6. Total lags used: 9
#11
autoplot(visitors)
Upward trend line, looks like the seasonality increases propotional to the level #11B
test = window(visitors, start = c(2003,4))
train = window(visitors, end = c(2004, 3))
hwmult = hw(train, seasonal="multiplicative", h=24)
autoplot(hwmult)
#11C Multiplicative is needed because the seasonal variation in the data increases as the level of the series increases.
#11D
etsfc <- train %>% ets() %>% forecast(h=24)
autoplot(etsfc)
etsadd.BCfc <- train %>% ets(lambda = BoxCox.lambda(train), additive.only=TRUE) %>% forecast(h=24)
autoplot(etsadd.BCfc)
snaive = snaive(train, h=24)
autoplot(snaive)
BCstl.ets <- train %>% stlm(
lambda = BoxCox.lambda(train),
s.window = 13,
robust=TRUE,
method="ets") %>% forecast(h=24)
autoplot(BCstl.ets)
#11E
accuracy(hwmult, test)
## ME RMSE MAE MPE MAPE MASE
## Training set -1.557919 14.70228 11.17152 -1.019484 4.452697 0.4268183
## Test set 15.090935 20.85700 16.04326 3.122066 3.359691 0.6129476
## ACF1 Theil's U
## Training set 0.09876254 NA
## Test set 0.21025230 0.2869292
accuracy(etsfc, test)
## ME RMSE MAE MPE MAPE MASE
## Training set 1.220635 14.90665 10.78433 0.2197614 4.018479 0.4120252
## Test set 31.260025 36.53961 31.26002 6.6962946 6.696295 1.1943180
## ACF1 Theil's U
## Training set -0.01726088 NA
## Test set 0.39874182 0.5090901
accuracy(etsadd.BCfc, test)
## ME RMSE MAE MPE MAPE MASE
## Training set -0.373716 15.55474 11.35863 -0.1677915 4.070118 0.4339668
## Test set 12.013636 19.11730 15.31311 2.3827550 3.229648 0.5850514
## ACF1 Theil's U
## Training set -0.05004163 NA
## Test set 0.23875318 0.2521544
accuracy(snaive, test)
## ME RMSE MAE MPE MAPE MASE ACF1
## Training set 16.78326 31.24472 26.17395 6.837756 10.14381 1.000000 0.6512811
## Test set 48.30000 55.23646 48.30000 11.417380 11.41738 1.845346 0.6747630
## Theil's U
## Training set NA
## Test set 0.7596856
accuracy(BCstl.ets, test)
## ME RMSE MAE MPE MAPE MASE
## Training set -0.8379729 13.88885 9.778233 -0.2528935 3.536527 0.3735864
## Test set 9.4686802 17.54139 13.069371 1.8664731 2.747569 0.4993274
## ACF1 Theil's U
## Training set -0.04339136 NA
## Test set -0.04401040 0.2405589
#12
str(ausbeer)
## Time-Series [1:218] from 1956 to 2010: 284 213 227 308 262 228 236 320 272 233 ...
head(ausbeer)
## Qtr1 Qtr2 Qtr3 Qtr4
## 1956 284 213 227 308
## 1957 262 228
autoplot(ausbeer)
ausbeer_train <- subset(
ausbeer, end = length(ausbeer) - 12
)
ausbeer_test <- subset(
ausbeer, start = length(ausbeer) - 11
)
ets_ausbeer_train <- forecast(
ets(ausbeer_train), h = 12
)
snaive_ausbeer_train <- snaive(ausbeer_train, h = 12)
stlf_ausbeer_train <- stlf(
ausbeer_train,
h = 12,
s.window = 5,
robust = TRUE,
lambda = BoxCox.lambda(ausbeer_train))
accuracy(ets_ausbeer_train, ausbeer_test)
## ME RMSE MAE MPE MAPE MASE
## Training set -0.3466095 15.781973 11.979955 -0.064073435 2.864311 0.7567076
## Test set 0.1272571 9.620828 8.919347 0.009981598 2.132836 0.5633859
## ACF1 Theil's U
## Training set -0.1942276 NA
## Test set 0.3763918 0.1783972
accuracy(snaive_ausbeer_train, ausbeer_test)
## ME RMSE MAE MPE MAPE MASE
## Training set 3.336634 19.67005 15.83168 0.9044009 3.771370 1.0000000
## Test set -2.916667 10.80509 9.75000 -0.6505927 2.338012 0.6158537
## ACF1 Theil's U
## Training set 0.0009690785 NA
## Test set 0.3254581810 0.1981463
accuracy(stlf_ausbeer_train, ausbeer_test)
## ME RMSE MAE MPE MAPE MASE
## Training set 0.5704833 13.61609 9.816091 0.1279204 2.334194 0.6200283
## Test set -4.0433841 10.11436 8.429747 -0.9670308 2.051915 0.5324605
## ACF1 Theil's U
## Training set -0.1131945 NA
## Test set 0.2865992 0.1689574
# Without RMSE, all the other errors show that the best model is STL + ETS(M, Ad, N).
autoplot(stlf_ausbeer_train) +
autolayer(ausbeer_test)
# The forecasts are similar to real data.
forecast.models <- function(y, h){
m <- frequency(y)
y_train <- subset(
y, end = length(y) - m*h
)
y_test <- subset(
y, start = length(y) - m*h + 1
)
# try each model and forecast.
ets_y_train <- forecast(
ets(y_train), h = m*h
)
snaive_y_train <- snaive(y_train, h = m*h)
stlf_y_train <- stlf(
y_train,
h = m*h,
s.window = m + 1,
robust = TRUE
)
stlf_y_train_with_BoxCox <- stlf(
y_train,
h = m*h,
s.window = m + 1,
robust = TRUE,
lambda = BoxCox.lambda(y_train))
# combine forecasts to models variable
models <- list(ets_y_train,
snaive_y_train,
stlf_y_train,
stlf_y_train_with_BoxCox)
names(models) <- c("ets", "snaive", "stlf", "stlf_with_BoxCox")
# get accuracy for each model using test set
acc_ets <- accuracy(ets_y_train, y_test)
acc_snaive <- accuracy(snaive_y_train, y_test)
acc_stlf <- accuracy(stlf_y_train, y_test)
acc_stlf_with_BoxCox <- accuracy(stlf_y_train_with_BoxCox, y_test)
# combine accuracies to accuracies variable.
accuracies <- list(acc_ets,
acc_snaive,
acc_stlf,
acc_stlf_with_BoxCox)
names(accuracies) <- c("acc_ets", "acc_snaive", "acc_stlf", "acc_stlf_with_BoxCox")
# return output values
output <- list(y_train, y_test, m, models, accuracies)
names(output) <- c("train", "test", "m", "models", "accuracies")
return(output)
}
# bricksq data case
fc_bricksq <- forecast.models(bricksq, 3)
fc_bricksq$accuracies
## $acc_ets
## ME RMSE MAE MPE MAPE MASE ACF1
## Training set 1.228708 21.96146 15.81586 0.2606171 3.912882 0.4299638 0.2038074
## Test set 37.682916 42.36696 37.68292 8.4157549 8.415755 1.0244329 0.6190546
## Theil's U
## Training set NA
## Test set 1.116608
##
## $acc_snaive
## ME RMSE MAE MPE MAPE MASE
## Training set 6.438849 50.25482 36.78417 1.430237 8.999949 1.0000000
## Test set 15.333333 37.15284 33.66667 3.231487 7.549326 0.9152487
## ACF1 Theil's U
## Training set 0.81169827 NA
## Test set -0.09314867 0.9538702
##
## $acc_stlf
## ME RMSE MAE MPE MAPE MASE
## Training set 1.318736 21.49082 14.41766 0.2855898 3.501287 0.3919528
## Test set 44.266931 50.20039 45.89301 10.0933739 10.487099 1.2476294
## ACF1 Theil's U
## Training set 0.1502759 NA
## Test set 0.1053316 1.31732
##
## $acc_stlf_with_BoxCox
## ME RMSE MAE MPE MAPE MASE ACF1
## Training set 1.42724 21.40466 14.30375 0.3185472 3.500221 0.3888560 0.1625098
## Test set 34.69481 40.13618 36.34649 7.7322091 8.132133 0.9881014 0.4746242
## Theil's U
## Training set NA
## Test set 1.04561
# All errors show that the best model is seasonal naive method.
autoplot(fc_bricksq$models$snaive) +
autolayer(fc_bricksq$test)
# In about an year the forecasts were similar to real data, but after that the real data increased exponentially while the trend of forecasts didn't change. But real data were still in the 80% prediction interval.
fc_dole <- forecast.models(dole, 3)
fc_dole$accuracies
## $acc_ets
## ME RMSE MAE MPE MAPE MASE
## Training set 98.00253 16130.58 9427.497 0.5518769 6.20867 0.2995409
## Test set 221647.42595 279668.65 221647.426 32.5447637 32.54476 7.0424271
## ACF1 Theil's U
## Training set 0.5139536 NA
## Test set 0.9394267 11.29943
##
## $acc_snaive
## ME RMSE MAE MPE MAPE MASE
## Training set 12606.58 56384.06 31473.16 3.350334 27.73651 1.000000
## Test set 160370.33 240830.92 186201.00 20.496197 27.38678 5.916184
## ACF1 Theil's U
## Training set 0.9781058 NA
## Test set 0.9208325 9.479785
##
## $acc_stlf
## ME RMSE MAE MPE MAPE MASE
## Training set -96.4811 7801.958 4530.06 -0.2719573 5.116149 0.1439341
## Test set 328005.9874 407547.190 328005.99 48.6435815 48.643581 10.4217690
## ACF1 Theil's U
## Training set 0.08037493 NA
## Test set 0.93373958 16.57033
##
## $acc_stlf_with_BoxCox
## ME RMSE MAE MPE MAPE MASE
## Training set 145.1468 6688.083 3659.404 0.1464869 3.82385 0.1162706
## Test set 205385.6547 268135.992 207317.238 29.3540384 29.85051 6.5871126
## ACF1 Theil's U
## Training set -0.09446256 NA
## Test set 0.93778748 10.68587
# All errors show best model is seasonal naive method.
autoplot(fc_dole$models$snaive) +
autolayer(fc_dole$test)
# The forecasts were completely wrong. Even the best model couldn't predict such change.
fc_a10 <- forecast.models(a10, 3)
fc_a10$accuracies
## $acc_ets
## ME RMSE MAE MPE MAPE MASE
## Training set 0.04378049 0.488989 0.3542285 0.2011915 3.993267 0.3611299
## Test set 1.62559331 2.562046 2.0101563 7.0011207 9.410027 2.0493197
## ACF1 Theil's U
## Training set -0.05238173 NA
## Test set 0.23062972 0.6929693
##
## $acc_snaive
## ME RMSE MAE MPE MAPE MASE ACF1
## Training set 0.9577207 1.177528 0.9808895 10.86283 11.15767 1.000000 0.3779746
## Test set 4.3181585 5.180738 4.3306974 19.80542 19.89352 4.415071 0.6384822
## Theil's U
## Training set NA
## Test set 1.383765
##
## $acc_stlf
## ME RMSE MAE MPE MAPE MASE
## Training set 0.06704027 0.6809938 0.4297557 0.3200743 4.732989 0.4381286
## Test set 1.83324369 3.1118106 2.4570607 7.0963340 11.223584 2.5049311
## ACF1 Theil's U
## Training set -0.01970509 NA
## Test set 0.23918322 0.8089697
##
## $acc_stlf_with_BoxCox
## ME RMSE MAE MPE MAPE MASE
## Training set 0.01686093 0.4244591 0.3098511 0.003515845 3.594686 0.3158879
## Test set 1.25869582 2.2242431 1.8428354 5.032385108 8.701050 1.8787390
## ACF1 Theil's U
## Training set -0.1780966 NA
## Test set 0.1502463 0.5964321
# All errors show that the best model is STL + ETS(A, A, N) with BoxCox transformation model.
autoplot(fc_a10$models$stlf_with_BoxCox) +
autolayer(fc_a10$test)
#The best model could follow the general trend, but a little short of predicting more fastly increasing trend.
fc_h02 <- forecast.models(h02, 3)
fc_h02$accuracies
## $acc_ets
## ME RMSE MAE MPE MAPE MASE
## Training set 0.001532209 0.04653434 0.03463451 0.0008075938 4.575471 0.5850192
## Test set 0.023667588 0.07667744 0.06442193 1.7152319315 7.030603 1.0881653
## ACF1 Theil's U
## Training set 0.07982687 NA
## Test set -0.12074883 0.450176
##
## $acc_snaive
## ME RMSE MAE MPE MAPE MASE
## Training set 0.03880677 0.07122149 0.05920234 5.220203 8.156509 1.00000
## Test set -0.01479486 0.08551752 0.07161055 -1.308298 7.884556 1.20959
## ACF1 Theil's U
## Training set 0.40465289 NA
## Test set 0.02264221 0.5009677
##
## $acc_stlf
## ME RMSE MAE MPE MAPE MASE
## Training set 0.001987465 0.04609626 0.03396307 -0.1760405 4.751272 0.5736778
## Test set 0.046520958 0.09174622 0.07544541 3.5302072 8.001263 1.2743653
## ACF1 Theil's U
## Training set 0.01953927 NA
## Test set 0.05661406 0.5085785
##
## $acc_stlf_with_BoxCox
## ME RMSE MAE MPE MAPE MASE
## Training set 0.003628017 0.04230875 0.03068561 0.02682146 4.159581 0.5183175
## Test set 0.031706735 0.07574975 0.06381807 2.51742657 6.903027 1.0779653
## ACF1 Theil's U
## Training set -0.09600393 NA
## Test set -0.25297574 0.4385025
# All errors show that the best model is STL + ETS(A, Ad, N) method.
autoplot(fc_h02$models$stlf_with_BoxCox) +
autolayer(fc_h02$test)
# The forecasts were similar to real data for the most part.
fc_usmelec <- forecast.models(usmelec, 3)
fc_usmelec$accuracies
## $acc_ets
## ME RMSE MAE MPE MAPE MASE
## Training set -0.07834851 7.447167 5.601963 -0.1168709 2.163495 0.6225637
## Test set -10.20080652 15.291359 13.123441 -3.1908161 3.926338 1.4584491
## ACF1 Theil's U
## Training set 0.2719249 NA
## Test set 0.4679496 0.4859495
##
## $acc_snaive
## ME RMSE MAE MPE MAPE MASE ACF1
## Training set 4.921564 11.58553 8.998217 2.000667 3.511648 1.000000 0.4841860
## Test set 5.475972 17.20037 13.494750 1.391437 3.767514 1.499714 0.2692544
## Theil's U
## Training set NA
## Test set 0.4765145
##
## $acc_stlf
## ME RMSE MAE MPE MAPE MASE
## Training set -0.07064178 6.659696 4.907696 -0.07729202 1.910234 0.5454076
## Test set -11.41131201 17.776488 15.918880 -3.66455560 4.779167 1.7691150
## ACF1 Theil's U
## Training set 0.1126383 NA
## Test set 0.5099758 0.5639709
##
## $acc_stlf_with_BoxCox
## ME RMSE MAE MPE MAPE MASE
## Training set -0.1351692 6.474779 4.761143 -0.05026415 1.848092 0.5291207
## Test set -19.9969503 24.406877 20.951753 -6.06977735 6.315723 2.3284338
## ACF1 Theil's U
## Training set 0.08255205 NA
## Test set 0.60877348 0.7777035
# Most of errors show the best model is ETS(M, A, M) method.
autoplot(fc_usmelec$models$ets) +
autolayer(fc_usmelec$test)
# Real data was within the prediction interval for the most part.
#Chapter 8 #2
ggtsdisplay(ibmclose)
# ACF plot shows that the autocorrelation values are bigger than critical value and decrease slowly. Also, r1 is large(near to 1) and positive. It means that the IBM stock is, predictable using lagged values. PACF plot shows that there is a strong correlation between IBM stock data and their 1 lagged values. It means that IBM stock data can be predicted by 1 lagged values. To get stationary data, IBM stock data need differencing. Differencing can make non-staionary data stationary.
transform.plot <- function(x){
lam <- BoxCox.lambda(x)
transformed <- BoxCox(x, lambda = lam)
tsdisplay(transformed)
return(paste("Box-Cox Lambda = ", round(lam, 4)))
}
data("usnetelec")
transform.plot(usnetelec)
## [1] "Box-Cox Lambda = 0.5168"
#The series needs one differencing in order to be stationary
data("usgdp")
transform.plot(usgdp)
## [1] "Box-Cox Lambda = 0.3664"
# The series needs one differencing in order to be stationary
data("mcopper")
transform.plot(mcopper)
## [1] "Box-Cox Lambda = 0.1919"
#The series needs two steps of differencing in order to be stationary
data("enplanements")
transform.plot(enplanements)
## [1] "Box-Cox Lambda = -0.2269"
#The series needs one differencing and seasonal differencing in order to be stationary
data("visitors")
transform.plot(visitors)
## [1] "Box-Cox Lambda = 0.2775"
## [1] "Box-Cox Lambda = 0.2775"
#5a
autoplot(austa)
fc_austa_autoarima <- forecast(
auto.arima(austa), h = 10
)
fc_austa_autoarima$model
## Series: austa
## ARIMA(0,1,1) with drift
##
## Coefficients:
## ma1 drift
## 0.3006 0.1735
## s.e. 0.1647 0.0390
##
## sigma^2 estimated as 0.03376: log likelihood=10.62
## AIC=-15.24 AICc=-14.46 BIC=-10.57
# ARIMA(0, 1, 1) with drift model was chosen.
checkresiduals(fc_austa_autoarima)
##
## Ljung-Box test
##
## data: Residuals from ARIMA(0,1,1) with drift
## Q* = 2.297, df = 5, p-value = 0.8067
##
## Model df: 2. Total lags used: 7
# The residuals are like white noise.
autoplot(fc_austa_autoarima)
# 5b
fc_austa_arima.0.1.1 <- forecast(
Arima(austa, order = c(0, 1, 1)), h = 10
)
autoplot(fc_austa_arima.0.1.1)
fc_austa_arima.0.1.0 <- forecast(
Arima(austa, order = c(0, 1, 0)), h = 10
)
autoplot(fc_austa_arima.0.1.0)
# the forecasts of both models are like the result of naive forecast. Increasing trend isn't reflected in the forecasts.
fc_austa_arima.0.1.1$upper - fc_austa_arima.0.1.0$upper
## Time Series:
## Start = 2016
## End = 2025
## Frequency = 1
## fc_austa_arima.0.1.1$upper.80% fc_austa_arima.0.1.1$upper.95%
## 2016 0.1138117 0.09101057
## 2017 0.2039418 0.22885273
## 2018 0.2527212 0.30345426
## 2019 0.2886706 0.35843413
## 2020 0.3180942 0.40343373
## 2021 0.3434784 0.44225553
## 2022 0.3660754 0.47681466
## 2023 0.3866116 0.50822207
## 2024 0.4055495 0.53718500
## 2025 0.4232034 0.56418442
fc_austa_arima.0.1.0$lower - fc_austa_arima.0.1.1$lower
## Time Series:
## Start = 2016
## End = 2025
## Frequency = 1
## fc_austa_arima.0.1.0$lower.80% fc_austa_arima.0.1.0$lower.95%
## 2016 -0.199956384 -0.22275751
## 2017 -0.109826244 -0.08491535
## 2018 -0.061046922 -0.01031382
## 2019 -0.025097519 0.04466605
## 2020 0.004326137 0.08966565
## 2021 0.029710347 0.12848745
## 2022 0.052307350 0.16304658
## 2023 0.072843552 0.19445399
## 2024 0.091781392 0.22341692
## 2025 0.109435361 0.25041634
# But prediction interval of ARIMA(0, 1, 1) model was generally larger than the one of ARIMA(0, 1, 0) model. I think that it is because of one more error term in ARIMA(0, 1, 1) model.
#5c
fc_austa_arima.2.1.3.drift <- forecast(
Arima(austa, order = c(2, 1, 3), include.drift = TRUE),
h = 10
)
autoplot(fc_austa_arima.2.1.3.drift)
# The forecasts are increasing, but the speed of the increase is decreasing.
drift_austa <- fc_austa_arima.2.1.3.drift$model$coef[6]
fc_austa_arima.2.1.3.nodrift <- fc_austa_arima.2.1.3.drift$mean - drift_austa*seq_len(10)
autoplot(fc_austa_arima.2.1.3.drift) +
autolayer(fc_austa_arima.2.1.3.nodrift)
#5d
fc_austa_arima.0.0.1.const <- forecast(
Arima(
austa, order = c(0, 0, 1), include.constant = TRUE
),
h = 10
)
autoplot(fc_austa_arima.0.0.1.const)
fc_austa_arima.0.0.0.const <- forecast(
Arima(austa, order = c(0, 0, 0), include.constant = TRUE),
h = 10
)
autoplot(fc_austa_arima.0.0.0.const)
# All of the forecasts are the mean of the data history. It is like the result of mean method.
#5e
fc_austa_arima.0.2.1 <- forecast(
Arima(austa, order = c(0, 2, 1)),
h = 10
)
autoplot(fc_austa_arima.0.2.1)
# the forecasts show increasing trend. PI is being larger for the farther future forecast.
#6a
y <- ts(numeric(100))
e <- rnorm(100)
for(i in 2:100)
y[i] <- 0.6*y[i-1] + e[i]
plot(y[i])
#6B
ar1 <- function(phi1){
y <- ts(numeric(100))
e <- rnorm(100)
for(i in 2:100){
y[i] <- phi1*y[i-1] + e[i]
}
return(y)
}
autoplot(ar1(0.3), series = "0.3") +
geom_line(size = 1, colour = "red") +
autolayer(y, series = "0.6", size = 1) +
autolayer(ar1(0.9), size = 1, series = "0.9") +
ylab("AR(1) models") +
guides(colour = guide_legend(title = "Phi1"))
#The variation in y increases as phi increases.
#6C
ma1 <- function(theta1){
y <- ts(numeric(100))
e <- rnorm(100)
for(i in 2:100){
y[i] <- theta1*e[i-1] + e[i]
}
return(y)
}
#6D
autoplot(ma1(0.3), series = "0.3") +
geom_line(size = 1, colour = "red") +
autolayer(y, series = "0.6", size = 1) +
autolayer(ma1(0.9), size = 1, series = "0.9") +
ylab("MA(1) models") +
guides(colour = guide_legend(title = "Theta1"))
#as theta increases, variation of y increases, just like phi. #6E
MYarima11 <- ts(numeric(50))
e <- rnorm(50)
for(i in 2:50){
MYarima11[i] <- 0.6*MYarima11[i-1] + 0.6*e[i-1] + e[i]
}
#6F
MYarima2 <- ts(numeric(50))
e <- rnorm(50)
for(i in 3:50){
MYarima2[i] <- -0.8*MYarima2[i-1] + 0.3*MYarima2[i-2] + e[i]
}
#6G
autoplot(MYarima11, series = "ARMA(1, 1)") +
autolayer(MYarima2, series = "AR(2)") +
ylab("y") +
guides(colour = guide_legend(title = "ARIMA Method"))
#7
# a
autoplot(wmurders)
# It looked like the data don't need seasonal differencing or Box-Cox transformation.
autoplot(diff(wmurders))
# It looked like 1 more differencing would be needed to make the data stationary. Differenced data slowly go to minus infinity.
ndiffs(wmurders)
## [1] 2
# ndiffs function shows that the data need 2 differencing.
autoplot(diff(wmurders, differences = 2))
kpss.test(diff(wmurders, differences = 2))
## Warning in kpss.test(diff(wmurders, differences = 2)): p-value greater than
## printed p-value
##
## KPSS Test for Level Stationarity
##
## data: diff(wmurders, differences = 2)
## KPSS Level = 0.045793, Truncation lag parameter = 3, p-value = 0.1
# twice differencing made the data stationary.
diff(wmurders, differences = 2) %>% ggtsdisplay()
# PACF is decaying. And there are significant spikes at lag 1, and 2 in the ACF, but none beyond lag 2. If the data can be modelled by ARIMA(0, 2, q) or ARIMA(p, 2, 0), I'm going to model the data by ARIMA(0, 2, 2).
# b
# ARIMA model of the data includes twice differencing. If there is a constant in the model, twice integrated contant will yield quadratic trend, which is dangerous for forecasting. Therefore I won't include a constant in the model.
# c
# (1 - B)^2*yt = (1 + theta1*B + theta2*B^2)*et
# d
wmurders_arima.0.2.2 <- Arima(wmurders,
order = c(0, 2, 2))
checkresiduals(wmurders_arima.0.2.2)
##
## Ljung-Box test
##
## data: Residuals from ARIMA(0,2,2)
## Q* = 11.764, df = 8, p-value = 0.1621
##
## Model df: 2. Total lags used: 10
# The residuals of the model can be thought of as white noise series. A little sorry that they aren't normally distributed. But it is satisfactory to get them.
# e
fc_wmurders_arima.0.2.2 <- forecast(
wmurders_arima.0.2.2, h = 3
)
# forecasts by Arima function
fc_wmurders_arima.0.2.2$mean
## Time Series:
## Start = 2005
## End = 2007
## Frequency = 1
## [1] 2.480525 2.374890 2.269256
# get forecasts by manual calculation
fc_wmurders_arima.0.2.2$model
## Series: wmurders
## ARIMA(0,2,2)
##
## Coefficients:
## ma1 ma2
## -1.0181 0.1470
## s.e. 0.1220 0.1156
##
## sigma^2 estimated as 0.04702: log likelihood=6.03
## AIC=-6.06 AICc=-5.57 BIC=-0.15
# formula
# (1 - B)^2*yt = (1 - 1.0181*B + 0.1470*B^2)*et
# yt = 2yt-1 - yt-2 + et - 1.0181*et-1 + 0.1470*et-2
years <- length(wmurders)
e <- fc_wmurders_arima.0.2.2$residuals
fc1 <- 2*wmurders[years] - wmurders[years - 1] - 1.0181*e[years] + 0.1470*e[years - 1]
fc2 <- 2*fc1 - wmurders[years] + 0.1470*e[years]
fc3 <- 2*fc2 - fc1
# forecasts by manual calculation
c(fc1, fc2, fc3)
## [1] 2.480523 2.374887 2.269252
# the forecasts are almost similar to the ones got by Arima function.
# f
autoplot(fc_wmurders_arima.0.2.2)
# g
fc_wmurders_autoarima <- forecast(
auto.arima(wmurders), h = 3
)
# Without RMSE, all errors show that ARIMA(0, 2, 2) is better than ARIMA(1, 2, 1).
accuracy(fc_wmurders_arima.0.2.2)
## ME RMSE MAE MPE MAPE MASE
## Training set -0.0113461 0.2088162 0.1525773 -0.2403396 4.331729 0.9382785
## ACF1
## Training set -0.05094066
accuracy(fc_wmurders_autoarima)
## ME RMSE MAE MPE MAPE MASE
## Training set -0.01065956 0.2072523 0.1528734 -0.2149476 4.335214 0.9400996
## ACF1
## Training set 0.02176343
# try using auto.arima function with stepwise and approximation options false.
fc_wmurders_autoarima2 <- forecast(
auto.arima(wmurders, stepwise = FALSE, approximation = FALSE),
h = 3
)
# It is ARIMA(0, 2, 3) model.
accuracy(fc_wmurders_autoarima2)
## ME RMSE MAE MPE MAPE MASE
## Training set -0.01336585 0.2016929 0.1531053 -0.3332051 4.387024 0.9415259
## ACF1
## Training set -0.03193856
# In this case, some errors were better while others were worse. I'll check residuals and ACF, PACF plots.
ggtsdisplay(diff(wmurders, differences = 2))
# It looked like that the data are similar to ARIMA(0, 2, 2) rather than ARIMA(0, 2, 3).
checkresiduals(fc_wmurders_arima.0.2.2)
##
## Ljung-Box test
##
## data: Residuals from ARIMA(0,2,2)
## Q* = 11.764, df = 8, p-value = 0.1621
##
## Model df: 2. Total lags used: 10
checkresiduals(fc_wmurders_autoarima2)
##
## Ljung-Box test
##
## data: Residuals from ARIMA(0,2,3)
## Q* = 10.706, df = 7, p-value = 0.152
##
## Model df: 3. Total lags used: 10
# almost similar residuals.
# Therefore I'll choose ARIMA(0, 2, 2).
#8
usgdparima = auto.arima(usgdp)
usgdparima
## Series: usgdp
## ARIMA(2,2,2)
##
## Coefficients:
## ar1 ar2 ma1 ma2
## -0.1228 0.3106 -0.5835 -0.3669
## s.e. 0.2869 0.0872 0.3004 0.2862
##
## sigma^2 estimated as 1604: log likelihood=-1199.57
## AIC=2409.13 AICc=2409.39 BIC=2426.43
usgdpets = ets(usgdp)
usgdpets
## ETS(A,A,N)
##
## Call:
## ets(y = usgdp)
##
## Smoothing parameters:
## alpha = 0.9999
## beta = 0.278
##
## Initial states:
## l = 1557.4589
## b = 18.6862
##
## sigma: 41.8895
##
## AIC AICc BIC
## 3072.303 3072.562 3089.643
checkresiduals(usgdparima)
##
## Ljung-Box test
##
## data: Residuals from ARIMA(2,2,2)
## Q* = 8.6247, df = 4, p-value = 0.0712
##
## Model df: 4. Total lags used: 8
usgdparima %>% forecast(h=8) %>% autoplot()
usgdpets %>% forecast(h=8) %>% autoplot
#10
autoplot(austourists)
#A
acf(austourists)
#B
pacf(austourists)
#C
ggtsdisplay(diff(austourists, lag=4))
auto.arima(austourists)
## Series: austourists
## ARIMA(1,0,0)(1,1,0)[4] with drift
##
## Coefficients:
## ar1 sar1 drift
## 0.4705 -0.5305 0.5489
## s.e. 0.1154 0.1122 0.0864
##
## sigma^2 estimated as 5.15: log likelihood=-142.48
## AIC=292.97 AICc=293.65 BIC=301.6
#11
mausmelec = ma(usmelec, order=12, centre = TRUE)
autoplot(mausmelec)
ndiffs(usmelec)
## [1] 1
elecarima = auto.arima(usmelec)
elecarima
## Series: usmelec
## ARIMA(1,0,2)(0,1,1)[12] with drift
##
## Coefficients:
## ar1 ma1 ma2 sma1 drift
## 0.9717 -0.4374 -0.2774 -0.7061 0.3834
## s.e. 0.0163 0.0483 0.0493 0.0310 0.0868
##
## sigma^2 estimated as 57.67: log likelihood=-1635.13
## AIC=3282.26 AICc=3282.44 BIC=3307.22
checkresiduals(elecarima)
##
## Ljung-Box test
##
## data: Residuals from ARIMA(1,0,2)(0,1,1)[12] with drift
## Q* = 42.725, df = 19, p-value = 0.001413
##
## Model df: 5. Total lags used: 24
elecfc = forecast(elecarima, h= 12*15)
autoplot(elecfc)
#13
autoplot(qauselec)
# The data need Box-Cox transformation to make the variations evenly over time.
lambda_qauselec <- BoxCox.lambda(qauselec)
# b
nsdiffs(qauselec)
## [1] 1
ndiffs(qauselec)
## [1] 1
# The data need 1 seasonal differencing.
kpss.test(diff(qauselec, lag = 4))
##
## KPSS Test for Level Stationarity
##
## data: diff(qauselec, lag = 4)
## KPSS Level = 0.39382, Truncation lag parameter = 4, p-value = 0.07982
# The data doesn't need first differencing.
# c
ggtsdisplay(diff(
BoxCox(qauselec, lambda_qauselec), lag = 4
))
ggtsdisplay(diff(diff(
BoxCox(qauselec, lambda_qauselec), lag = 4
)))
qauselec_arima0.0.1.0.1.1.4 <- Arima(
qauselec, lambda = lambda_qauselec,
order = c(0, 0, 1), seasonal = c(0, 1, 1)
)
qauselec_arima0.0.1.0.1.1.4
## Series: qauselec
## ARIMA(0,0,1)(0,1,1)[4]
## Box Cox transformation: lambda= 0.5195274
##
## Coefficients:
## ma1 sma1
## 0.6495 0.2738
## s.e. 0.0746 0.0642
##
## sigma^2 estimated as 0.03639: log likelihood=51.5
## AIC=-97.01 AICc=-96.89 BIC=-86.91
qauselec_arima0.1.1.0.1.1.4 <- Arima(
qauselec, lambda = lambda_qauselec,
order = c(0, 1, 1), seasonal = c(0, 1, 1)
)
qauselec_arima0.1.1.0.1.1.4
## Series: qauselec
## ARIMA(0,1,1)(0,1,1)[4]
## Box Cox transformation: lambda= 0.5195274
##
## Coefficients:
## ma1 sma1
## -0.4976 -0.6910
## s.e. 0.0772 0.0418
##
## sigma^2 estimated as 0.01435: log likelihood=149.29
## AIC=-292.59 AICc=-292.47 BIC=-282.5
qauselec_arima0.1.1.0.1.2.4 <- Arima(
qauselec, lambda = lambda_qauselec,
order = c(0, 1, 1), seasonal = c(0, 1, 2)
)
qauselec_arima0.1.1.0.1.2.4
## Series: qauselec
## ARIMA(0,1,1)(0,1,2)[4]
## Box Cox transformation: lambda= 0.5195274
##
## Coefficients:
## ma1 sma1 sma2
## -0.5037 -0.7993 0.1249
## s.e. 0.0710 0.0870 0.0864
##
## sigma^2 estimated as 0.01425: log likelihood=150.36
## AIC=-292.73 AICc=-292.53 BIC=-279.28
qauselec_autoarima <- auto.arima(
qauselec, lambda = lambda_qauselec
)
qauselec_autoarima
## Series: qauselec
## ARIMA(1,1,1)(1,1,2)[4]
## Box Cox transformation: lambda= 0.5195274
##
## Coefficients:
## ar1 ma1 sar1 sma1 sma2
## 0.2523 -0.6905 0.8878 -1.6954 0.7641
## s.e. 0.1562 0.1279 0.0864 0.0983 0.0772
##
## sigma^2 estimated as 0.01345: log likelihood=156.42
## AIC=-300.84 AICc=-300.43 BIC=-280.67
# According to AIC values, ARIMA(1, 1, 1)(1, 1, 2)[4] with Box-Cox transformation is the best model
# d
checkresiduals(qauselec_autoarima)
##
## Ljung-Box test
##
## data: Residuals from ARIMA(1,1,1)(1,1,2)[4]
## Q* = 10.605, df = 3, p-value = 0.01407
##
## Model df: 5. Total lags used: 8
# The residuals aren't like white noise.
# try using other models.
checkresiduals(qauselec_arima0.0.1.0.1.1.4)
##
## Ljung-Box test
##
## data: Residuals from ARIMA(0,0,1)(0,1,1)[4]
## Q* = 84.595, df = 6, p-value = 4.441e-16
##
## Model df: 2. Total lags used: 8
checkresiduals(qauselec_arima0.1.1.0.1.1.4)
##
## Ljung-Box test
##
## data: Residuals from ARIMA(0,1,1)(0,1,1)[4]
## Q* = 15.102, df = 6, p-value = 0.01948
##
## Model df: 2. Total lags used: 8
checkresiduals(qauselec_arima0.1.1.0.1.2.4)
##
## Ljung-Box test
##
## data: Residuals from ARIMA(0,1,1)(0,1,2)[4]
## Q* = 13.684, df = 5, p-value = 0.01775
##
## Model df: 3. Total lags used: 8
# The residuals don't resemble white noise so I'm going to use the best model.
fc_qauselec_autoarima <- forecast(
qauselec_autoarima, h = 8
)
autoplot(fc_qauselec_autoarima)
# The forecasts are reasonable.
# f. Compare the forecasts obtained using ets().
fc_qauselec_ets <- forecast(
ets(qauselec), h = 8
)
autoplot(fc_qauselec_ets)
# These forecasts also are reasonable.
#17
## [1] 525.8100 513.8023 499.6705
## Time Series:
## Start = 1969
## End = 1971
## Frequency = 1
## [1] 526.2057 514.0658 500.0111
## [1] 526.2057 514.0658 500.0111