## Loading required package: forecast
## Registered S3 method overwritten by 'quantmod':
## method from
## as.zoo.data.frame zoo
## Loading required package: fma
## Loading required package: expsmooth
## Loading required package: lmtest
## Loading required package: zoo
##
## Attaching package: 'zoo'
## The following objects are masked from 'package:base':
##
## as.Date, as.Date.numeric
## Loading required package: tseries
## -- Attaching packages ---------------------------------------------- fpp2 2.4 --
## v ggplot2 3.3.5
##
##
## Attaching package: 'fpp2'
## The following objects are masked from 'package:fpp':
##
## ausair, ausbeer, austa, austourists, debitcards, departures,
## elecequip, euretail, guinearice, oil, sunspotarea, usmelec
## -- Attaching packages -------------------------------------------- fpp3 0.4.0 --
## v tibble 3.1.5 v tsibble 1.1.0
## v dplyr 1.0.7 v tsibbledata 0.3.0
## v tidyr 1.1.4 v feasts 0.2.2
## v lubridate 1.7.10 v fable 0.3.1
## -- Conflicts ------------------------------------------------- fpp3_conflicts --
## x lubridate::date() masks base::date()
## x dplyr::filter() masks stats::filter()
## x fabletools::forecast() masks forecast::forecast()
## x tsibble::index() masks zoo::index()
## x tsibble::intersect() masks base::intersect()
## x tsibble::interval() masks lubridate::interval()
## x dplyr::lag() masks stats::lag()
## x tsibble::setdiff() masks base::setdiff()
## x tsibble::union() masks base::union()
##
## Attaching package: 'fpp3'
## The following object is masked from 'package:fpp2':
##
## insurance
## The following object is masked from 'package:fpp':
##
## insurance
##
## Attaching package: 'gridExtra'
## The following object is masked from 'package:dplyr':
##
## combine
##
## Attaching package: 'seasonal'
## The following object is masked from 'package:tibble':
##
## view
We will be looking at monthly Nike (NKE) adjusted closing price over the past 5 years. The objective of this assignment is to test multiple forecasting techniques and assess their performance.
autoplot(NKE, main = "NIKE") + xlab("Time (Months)") +
ylab("Adjusted Closing Price (USD)")
ggtsdisplay(NKE)
From the ACF plot, we can see some autocorrelation based on the trend of the plot. From the PACF plot, the data is non-stationary.
# Non-Damped Holt-Winters' Additive vs Multiplicative
HW_Add1 = hw(NKE, h = 10, seasonal = "additive")
HW_Mult1 = hw(NKE, h = 10, seasonal = "multiplicative")
# Plot Holt-Winters" Fitted
autoplot(NKE, main = "Holt-Winters' Additive vs Multiplicative") +
autolayer(fitted(HW_Add1), series = "Additive Method") +
autolayer(fitted(HW_Mult1), series = "Multiplicative Method") +
xlab("Time (Months)") + ylab("Adjusted Closing Price (USD)")
# accuracy measurements
accuracy(HW_Add1)
## ME RMSE MAE MPE MAPE MASE
## Training set -0.009310702 6.498002 4.81517 -0.7244294 5.423487 0.1968716
## ACF1
## Training set 0.0873819
accuracy(HW_Mult1)
## ME RMSE MAE MPE MAPE MASE
## Training set 0.1660017 6.709437 5.125887 -0.1149763 5.789773 0.2095755
## ACF1
## Training set 0.2968867
# Forecasts
forecast(HW_Add1, h = 10)
## Point Forecast Lo 80 Hi 80 Lo 95 Hi 95
## Feb 6 170.1461 160.4505 179.8417 155.3179 184.9742
## Mar 6 167.0778 155.2651 178.8906 149.0118 185.1438
## Apr 6 167.5960 153.9913 181.2008 146.7893 188.4027
## May 6 170.8152 155.6280 186.0024 147.5883 194.0420
## Jun 6 178.9087 162.2886 195.5288 153.4905 204.3269
## Jul 6 180.6256 162.6864 198.5648 153.1899 208.0613
## Aug 6 181.5393 162.3712 200.7075 152.2241 210.8545
## Sep 6 184.9877 164.6645 205.3110 153.9061 216.0694
## Oct 6 185.3719 163.9556 206.7883 152.6184 218.1255
## Nov 6 191.3464 168.8897 213.8031 157.0018 225.6909
forecast(HW_Mult1, h = 10)
## Point Forecast Lo 80 Hi 80 Lo 95 Hi 95
## Feb 6 172.2188 153.6063 190.8313 143.7534 200.6841
## Mar 6 165.0464 145.4126 184.6803 135.0190 195.0738
## Apr 6 165.9561 144.0409 187.8713 132.4397 199.4725
## May 6 166.6291 142.1212 191.1371 129.1474 204.1108
## Jun 6 178.4548 149.2296 207.6800 133.7587 223.1509
## Jul 6 184.5169 150.9576 218.0762 133.1924 235.8414
## Aug 6 188.9352 150.9201 226.9502 130.7962 247.0742
## Sep 6 189.1304 147.2199 231.0410 125.0337 253.2271
## Oct 6 190.1973 143.9960 236.3986 119.5385 260.8561
## Nov 6 202.0374 148.4874 255.5874 120.1398 283.9350
These accuracy measurements show that these models are decent. Based on the RMSE, the additive method works better than the multiplicative. We next try to use the damped method.
# Damped Holt-Winters' Additive vs Multiplicative
HW_Add2 = hw(NKE, h = 10, seasonal = "additive", damped = TRUE)
HW_Mult2 = hw(NKE, h = 10, seasonal = "multiplicative", damped = TRUE)
# Plot Holt-Winters" Fitted
autoplot(NKE, main = "Holt-Winters' Additive vs Multiplicative") +
autolayer(fitted(HW_Add2), series = "Additive Method") +
autolayer(fitted(HW_Mult2), series = "Multiplicative Method") +
xlab("Time (Months)") + ylab("Adjusted Closing Price (USD)")
# accuracy measurements
accuracy(HW_Add2)
## ME RMSE MAE MPE MAPE MASE ACF1
## Training set 1.086216 6.672154 4.786691 0.7881414 5.285359 0.1957072 0.03726941
accuracy(HW_Mult2)
## ME RMSE MAE MPE MAPE MASE
## Training set 0.625629 6.316295 4.801755 -0.02773123 5.402625 0.1963231
## ACF1
## Training set 0.1472974
# Forecasts
forecast(HW_Add2, h = 10)
## Point Forecast Lo 80 Hi 80 Lo 95 Hi 95
## Feb 6 171.1818 161.1139 181.2498 155.7843 186.5794
## Mar 6 168.8404 156.2452 181.4355 149.5777 188.1030
## Apr 6 169.7679 154.8757 184.6601 146.9923 192.5436
## May 6 173.1627 156.1058 190.2197 147.0763 199.2491
## Jun 6 181.1879 162.0497 200.3262 151.9185 210.4573
## Jul 6 183.6054 162.4416 204.7691 151.2382 215.9726
## Aug 6 183.0098 159.8590 206.1605 147.6038 218.4157
## Sep 6 187.1538 162.0434 212.2642 148.7507 225.5568
## Oct 6 185.9043 158.8538 212.9548 144.5341 227.2745
## Nov 6 190.3224 161.3460 219.2989 146.0068 234.6380
forecast(HW_Mult2, h = 10)
## Point Forecast Lo 80 Hi 80 Lo 95 Hi 95
## Feb 6 167.5156 150.2236 184.8077 141.0697 193.9616
## Mar 6 160.8686 141.3993 180.3379 131.0928 190.6444
## Apr 6 162.6630 140.1959 185.1301 128.3026 197.0234
## May 6 164.0414 138.6535 189.4292 125.2140 202.8687
## Jun 6 177.4795 147.1114 207.8476 131.0355 223.9236
## Jul 6 183.3751 149.0396 217.7105 130.8636 235.8866
## Aug 6 184.0857 146.6745 221.4969 126.8702 241.3011
## Sep 6 182.0879 142.1914 221.9844 121.0715 243.1043
## Oct 6 186.3111 142.5454 230.0769 119.3772 253.2451
## Nov 6 193.7242 145.1670 242.2815 119.4623 267.9862
Analyzing this, the RMSE shows the multiplicative damped method is the best out of the 4 Holt-Winters model.
ar_model = auto.arima(NKE)
checkresiduals(ar_model)
##
## Ljung-Box test
##
## data: Residuals from ARIMA(0,1,0) with drift
## Q* = 9.911, df = 11, p-value = 0.5384
##
## Model df: 1. Total lags used: 12
autoplot(NKE, main = "Nike ARIMA Forecast") +
autolayer(fitted(ar_model), series = "ARIMA") +
xlab("Time (Months)") + ylab("Adjusted Closing Price (USD)")
forecast(ar_model, h = 12)
## Point Forecast Lo 80 Hi 80 Lo 95 Hi 95
## Feb 6 173.3078 164.2731 182.3426 159.4904 187.1252
## Mar 6 175.3257 162.5487 188.1027 155.7849 194.8664
## Apr 6 177.3435 161.6949 192.9921 153.4111 201.2760
## May 6 179.3614 161.2919 197.4308 151.7266 206.9962
## Jun 6 181.3792 161.1770 201.5815 150.4826 212.2759
## Jul 6 183.3971 161.2666 205.5275 149.5515 217.2427
## Aug 6 185.4149 161.5113 209.3185 148.8575 221.9723
## Sep 6 187.4328 161.8787 212.9868 148.3512 226.5143
## Oct 6 189.4506 162.3464 216.5548 147.9984 230.9028
## Nov 6 191.4684 162.8982 220.0387 147.7740 235.1629
## Dec 6 193.4863 163.5215 223.4511 147.6591 239.3134
## Jan 7 195.5041 164.2070 226.8013 147.6392 243.3690
accuracy(ar_model)
## ME RMSE MAE MPE MAPE MASE
## Training set 0.000790187 6.933293 5.076957 -0.6007268 5.384868 0.207575
## ACF1
## Training set -0.09901864
THe ARIMA(0,1,0) with drift was the best ARIMA model produced by the auto.arima() function. Based on the RMSE, we can see the ARIMA model is the worst comparing to the Holt-Winters’ model. From the residual histogram, we are looking for a normal trend. We can see that majority of the residuals are in the middle of the chart with some outliers on both sides. This histogram is not perfect, but it does follow the normal plot characteristics.
ets_model = ets(NKE)
checkresiduals(ets_model)
##
## Ljung-Box test
##
## data: Residuals from ETS(M,A,N)
## Q* = 6.8083, df = 8, p-value = 0.5574
##
## Model df: 4. Total lags used: 12
autoplot(NKE, main = "NKE ETS Forecast") +
autolayer(fitted(ets_model), series = "ETS") +
xlab("Time (Months") + ylab("Adjusted Closing Price (USD)")
forecast(ets_model, h = 12)
## Point Forecast Lo 80 Hi 80 Lo 95 Hi 95
## Feb 6 173.1394 157.9440 188.3348 149.9001 196.3787
## Mar 6 174.8130 154.6318 194.9942 143.9485 205.6775
## Apr 6 176.4866 152.2445 200.7287 139.4115 213.5617
## May 6 178.1602 150.3726 205.9478 135.6628 220.6576
## Jun 6 179.8338 148.8382 210.8294 132.4301 227.2375
## Jul 6 181.5074 147.5446 215.4702 129.5658 233.4490
## Aug 6 183.1810 146.4329 219.9290 126.9797 239.3823
## Sep 6 184.8546 145.4639 224.2453 124.6118 245.0974
## Oct 6 186.5282 144.6100 228.4464 122.4199 250.6365
## Nov 6 188.2018 143.8510 232.5526 120.3731 256.0305
## Dec 6 189.8754 143.1715 236.5793 118.4479 261.3028
## Jan 7 191.5490 142.5596 240.5384 116.6262 266.4718
accuracy(ets_model)
## ME RMSE MAE MPE MAPE MASE
## Training set 0.3996441 6.883047 5.053174 -0.2145753 5.338165 0.2066026
## ACF1
## Training set 0.004115949
Lastly, we take a look at an exponential smoothing model. The histogram of the residuals for the ETS model shows that this model performs worse that the ARIMA plot. The RMSE metric shows this produces better results than the ARIMA, but the Damped Holt-Winters Multiplicative model works the best for the Nike equity prices.