| Exercise | Finding |
|---|---|
| 8.1 Pigs | alpha = 0.322, l[0] = 100,646.6. Manual and R 95% intervals are nearly identical. |
| 8.5 Algeria | ANN beats AAN on RMSE (5.87 vs 5.89) and AICc (447 vs 452). No trend needed. |
| 8.6 China GDP | Box-Cox/log trends explode; damped models give more plausible forecasts. |
| 8.7 Gas | Multiplicative seasonality; HWm preferred (AICc 1682 vs 1685). |
| 8.8 Retail | HWmd has best test RMSE (1.15) and beats SNAIVE (1.55); HWm does not (1.78). |
| 8.9 STL + ETS | RMSE 1.13, narrowly beats HWmd (1.15). |
pigs <- aus_livestock |> filter(Animal == "Pigs", State == "Victoria")
fit81 <- pigs |> model(ETS(Count ~ error("A") + trend("N") + season("N")))
report(fit81)
## Series: Count
## Model: ETS(A,N,N)
## Smoothing parameters:
## alpha = 0.3221247
##
## Initial states:
## l[0]
## 100646.6
##
## sigma^2: 87480760
##
## AIC AICc BIC
## 13737.10 13737.14 13750.07
fc81 <- fit81 |> forecast(h = 4)
fc81 |> autoplot(pigs |> filter(year(Month) >= 2010))
s <- augment(fit81) |> pull(.resid) |> sd(na.rm = TRUE)
c(lower = fc81$.mean[1] - 1.96 * s, upper = fc81$.mean[1] + 1.96 * s)
## lower upper
## 76871.01 113502.10
fc81 |> hilo(level = 95) |> slice(1) |> pull(`95%`)
## <hilo[1]>
## [1] [76854.79, 113518.3]95
Findings: alpha = 0.322 and l[0] = 100,646.6. The forecast is flat at the last smoothed level. My manual interval [76,871, 113,502] is very close to R’s [76,855, 113,518]. R’s is slightly wider because it uses the exact forecast variance.
alg <- global_economy |> filter(Country == "Algeria")
alg |> autoplot(Exports)
fit85 <- alg |> model(
ANN = ETS(Exports ~ error("A") + trend("N") + season("N")),
AAN = ETS(Exports ~ error("A") + trend("A") + season("N")))
fit85 |> forecast(h = 5) |> autoplot(alg, level = NULL)
accuracy(fit85) |> select(.model, RMSE)
glance(fit85) |> select(.model, AICc)
fc85 <- fit85 |> forecast(h = 1)
rmse85 <- accuracy(fit85)$RMSE
fc85 |> mutate(lo = .mean - 1.96 * rmse85, hi = .mean + 1.96 * rmse85) |>
as_tibble() |> select(.model, .mean, lo, hi)
fc85 |> hilo(level = 95) |> as_tibble() |> select(.model, `95%`)
Findings: Exports have no seasonality and no persistent trend, just large fluctuations. ANN has the lower RMSE (5.87 vs 5.89) and lower AICc (447 vs 452), so it is the better model. Manual intervals (ANN [10.9, 33.9], AAN [10.4, 33.5]) are close to R’s (ANN [10.75, 34.14], AAN [10.02, 33.94]), with R’s slightly wider.
chn <- global_economy |> filter(Country == "China")
lam6 <- chn |> features(GDP, guerrero) |> pull(lambda_guerrero)
fit86 <- chn |> model(
AAN = ETS(GDP ~ error("A") + trend("A") + season("N")),
damped = ETS(GDP ~ error("A") + trend("Ad") + season("N")),
boxcox = ETS(box_cox(GDP, lam6) ~ error("A") + trend("A") + season("N")),
boxcox_d = ETS(box_cox(GDP, lam6) ~ error("A") + trend("Ad") + season("N")),
log_damped = ETS(log(GDP) ~ error("A") + trend("Ad") + season("N")))
fit86 |> forecast(h = 30) |> autoplot(chn, level = NULL)
Findings: AAN and damped give the lowest, roughly linear forecasts. Box-Cox and log curve upward because the transformation makes growth exponential-like in original units. The undamped Box-Cox model reaches about 1e15 by 2050, which is unrealistic. Damping tempers it, so damped models are more plausible over 30 years.
fit87 <- aus_production |> model(
HWm = ETS(Gas ~ error("M") + trend("A") + season("M")),
HWmd = ETS(Gas ~ error("M") + trend("Ad") + season("M")))
fit87 |> forecast(h = "5 years") |>
autoplot(aus_production |> filter(year(Quarter) > 1990), level = NULL)
accuracy(fit87)
glance(fit87)
Findings: Seasonal swings grow with the level, so multiplicative seasonality is needed. RMSE is almost identical (4.60 vs 4.59), but HWm has the lower AICc (1682 vs 1685). The trend is close to linear, so damping is not needed.
set.seed(12345678)
myseries <- aus_retail |>
filter(`Series ID` == sample(aus_retail$`Series ID`, 1))
myseries |> autoplot(Turnover)
fit88 <- myseries |> model(
HWm = ETS(Turnover ~ error("M") + trend("A") + season("M")),
HWmd = ETS(Turnover ~ error("M") + trend("Ad") + season("M")))
accuracy(fit88) |> select(.model, RMSE)
fit88 |> select(HWm) |> gg_tsresiduals()
augment(fit88) |> features(.innov, ljung_box, lag = 24)
train <- myseries |> filter(year(Month) <= 2010)
test <- anti_join(myseries, train, by = "Month")
fit88t <- train |> model(
HWm = ETS(Turnover ~ error("M") + trend("A") + season("M")),
HWmd = ETS(Turnover ~ error("M") + trend("Ad") + season("M")),
snaive = SNAIVE(Turnover))
fit88t |> forecast(new_data = test) |> accuracy(myseries) |> select(.model, RMSE)
Findings: Seasonal swings grow with the level, so seasonality is multiplicative. HWm has the slightly lower one-step RMSE (0.613 vs 0.616). Its Ljung-Box p-value is 0.0765 (above 0.05, borderline); HWmd’s is 0.472. On the test set HWmd is best (1.15), SNAIVE is 1.55, and HWm is worst (1.78). So HWmd beats the seasonal naive benchmark, but HWm does not.
lam9 <- myseries |> features(Turnover, guerrero) |> pull(lambda_guerrero)
fit89 <- train |> model(
stl_ets = decomposition_model(
STL(box_cox(Turnover, lam9) ~ season(window = "periodic"), robust = TRUE),
ETS(season_adjust ~ error("A") + trend("Ad") + season("N"))))
fit89 |> forecast(new_data = test) |> accuracy(myseries) |> select(.model, RMSE)
Findings: STL + ETS has test RMSE 1.13, slightly lower than the best model from 8.8(e), HWmd at 1.15. STL + ETS wins, but only narrowly.