## ----include = FALSE---------------------------------------------------------- knitr::opts_chunk$set( collapse = TRUE, comment = "#>", dev = "png", # fig.path = "figures/tscv-", fig.height = 5, fig.width = 7 ) ## ----packages, message = FALSE, warning = FALSE------------------------------- # Load relevant packages library(tscv) library(tidyverse) library(tsibble) library(fable) library(feasts) ## ----abbreviations, echo=FALSE, warning=FALSE, message=FALSE, results='hide'---- Sys.setlocale("LC_TIME", "C") ## ----clean_data, fig.alt = "Plot raw data"------------------------------------ series_id = "bidding_zone" value_id = "value" index_id = "time" context <- list( series_id = series_id, value_id = value_id, index_id = index_id ) # Prepare data set main_frame <- elec_price %>% filter(bidding_zone %in% c("DE", "FR", "NO1", "SE1")) main_frame main_frame %>% plot_line( x = time, y = value, color = bidding_zone, facet_var = bidding_zone, title = "Day-ahead Electricity Spot Price", subtitle = "2019-01-01 to 2020-12-31", xlab = "Time", ylab = "[EUR/MWh]", caption = "Data: ENTSO-E Transparency" ) summarise_data( .data = main_frame, context = context ) summarise_stats( .data = main_frame, context = context ) ## ----split_data--------------------------------------------------------------- # Setup for time series cross validation type = "first" value = 2400 # size for training window n_ahead = 24 # size for testing window (= forecast horizon) n_skip = 23 # skip 23 observations n_lag = 0 # no lag mode = "slide" # fixed window approach exceed = FALSE # only pseudo out-of-sample forecast split_frame <- make_split( main_frame = main_frame, context = context, type = type, value = value, n_ahead = n_ahead, n_skip = n_skip, n_lag = n_lag, mode = mode, exceed = exceed ) # For illustration, only the first 50 splits are used split_frame <- split_frame %>% filter(split %in% c(1:50)) split_frame ## ----train_models------------------------------------------------------------- # Slice training data from main_frame according to split_frame train_frame <- slice_train( main_frame = main_frame, split_frame = split_frame, context = context ) train_frame # Convert tibble to tsibble train_frame <- train_frame %>% as_tsibble( index = time, key = c(bidding_zone, split) ) train_frame # Model training via fabletools::model() model_frame <- train_frame %>% model( "SNAIVE" = SNAIVE(value ~ lag("week")), "STL-NAIVE" = decomposition_model(STL(value), NAIVE(season_adjust)), "SNAIVE2" = SNAIVE2(value), "SMEDIAN" = SMEDIAN(value ~ lag("week")) ) model_frame # Forecasting via fabletools::forecast() fable_frame <- model_frame %>% forecast(h = n_ahead) fable_frame # Convert fable_frame (fable) to future_frame (tibble) future_frame <- make_future( fable = fable_frame, context = context ) future_frame ## ----accuracy_horizon, fig.alt = "Plot accuracy by horizon"------------------- # Estimate accuracy metrics by forecast horizon accuracy_horizon <- make_accuracy( future_frame = future_frame, main_frame = main_frame, context = context, dimension = "horizon" ) accuracy_horizon # Visualize results accuracy_horizon %>% filter(metric == "MAE") %>% plot_line( x = n, y = value, facet_var = bidding_zone, facet_nrow = 1, color = model, title = "Evaluation of forecast accuracy by forecast horizon", subtitle = "Mean absolute error (MAE)", xlab = "Forecast horizon (n-step-ahead)", caption = "Data: ENTSO-E Transparency, own calculation" ) ## ----accuracy_split, fig.alt = "Plot accuracy by split"----------------------- # Estimate accuracy metrics by forecast horizon accuracy_split <- make_accuracy( future_frame = future_frame, main_frame = main_frame, context = context, dimension = "split" ) accuracy_split # Visualize results accuracy_split %>% filter(metric == "MAE") %>% plot_line( x = n, y = value, facet_var = bidding_zone, facet_nrow = 1, color = model, title = "Evaluation of forecast accuracy by split", subtitle = "Mean absolute error (MAE)", xlab = "Split", caption = "Data: ENTSO-E Transparency, own calculation" )