<- vic_elec %>%
energy_series filter_index(~ "2014-12-31") %>%
::select(Time, Demand, Temperature) %>%
dplyrdrop_na()
Activity34
Extending ETS Models with Predictors
Data Prep
- Use historical energy demand + temperature
- Ensure alignment in timestamps (
drop_na()
)
Step 1 - Baseline ETS Model
# 1. ETS for Demand (non-seasonal)
<- energy_series %>% model(ETS(Demand))
demand_ets <- demand_ets %>%
demand_ets_fc forecast(h = "1 week") %>%
as_tibble() %>%
rename(mean = .mean) %>%
mutate(Model = "ETS")
\[\text{Demand}_t = \text{Level}_{t-1} + \text{Error}_t\]
The first model uses ETS (Error-Trend-Seasonal) for demand alone. This is limited because:
- Ignores temperature (known predictor)
- Assumes patterns are purely endogenous
Step 2 - ARIMAX with Temperature
# 2. ARIMAX with temperature forecasts
# First forecast temperature
<- energy_series %>% model(ETS(Temperature))
temp_ets <- temp_ets %>%
temp_fc forecast(h = "1 week") %>%
as_tibble() %>%
::select(Time, Temperature = .mean)
dplyr
<- energy_series %>% model(ARIMA(Demand ~ Temperature))
demand_dr
<- demand_dr %>%
demand_dr_fc forecast(new_data = temp_fc %>% as_tsibble(index = Time)) %>%
as_tibble() %>%
rename(mean = .mean) %>%
mutate(Model = "ARIMAX")
\[\text{Demand}_t = \phi_1 \text{Demand}_{t-1} + \beta \text{Temperature}_t + \epsilon_t\]
Improvement: Adds temperature as exogenous predictor.
But requires temperature forecasts - introduces error propagation if temperature predictions are poor.
Part 2: Why VAR Models Shine for Short-Term
Vector Autoregression (VAR)
\[\begin{cases} \text{Demand}_t = \alpha_1 + \sum_{i=1}^p \phi_{1i}\text{Demand}_{t-i} + \sum_{i=1}^p \psi_{1i}\text{Temp}_{t-i} \\ \text{Temp}_t = \alpha_2 + \sum_{i=1}^p \phi_{2i}\text{Demand}_{t-i} + \sum_{i=1}^p \psi_{2i}\text{Temp}_{t-i} \end{cases}\]
Key Advantages
- Handles bidirectional relationships (temperature ↔︎ demand)
- Captures lagged cross-effects
- Better for short-term forecasts where system inertia matters
3. Critical Implementation Details
- Differencing: Makes series stationary for VAR (
difference()
) - Lag choice: 48 lags = 24hr periodicity (half-hourly data)
- Forecast alignment:
\[\text{VarForecast}_t = \text{LastObs} + \sum \text{DifferencedForecasts}_t\]
(Reverse the differencing through cumulative sums)
4. Comparison
- ETS: Good baseline but misses covariates
- ARIMAX: Better with good temp forecasts
- VAR: Best for short-term co-movements, no external forecast needed
# 3. VAR with tsDyn implementation
<- energy_series %>% as_tibble() %>%
var_data select(Demand, Temperature) %>%
mutate(across(everything(), difference)) %>%
::drop_na()
tidyr
<- tsDyn::lineVar(var_data, lag = 48)
var_model <- predict(var_model, n.ahead = 336)
var_fc
# Align VAR forecasts with original scale
<- tail(energy_series, 1)
last_obs <- tibble(
var_fc_demand Time = demand_ets_fc$Time,
mean = last_obs$Demand + cumsum(var_fc[,1]),
Model = "VAR"
)
# Combine forecasts
<- bind_rows(
combined_fc %>% select(Time, Model, mean),
demand_ets_fc %>% select(Time, Model, mean),
demand_dr_fc
var_fc_demand )
# Plot with accurate comparisons
ggplot() +
geom_line(data = energy_series %>% tail(2016), # Last 2 weeks
aes(x = Time, y = Demand), color = "gray40") +
geom_line(data = combined_fc,
aes(x = Time, y = mean, color = Model), linewidth = 0.8) +
labs(title = "Electricity Demand Forecasts: Three Methodologies",
subtitle = "Using actual temperature forecasts for ARIMAX\nVAR with 48-lag (24h) differenced model",
y = "Demand (MW)") +
theme_minimal() +
scale_color_viridis_d(option = "H")