Time Series Forecasting with fable

· 4 min read · Updated March 12, 2026 · intermediate
r time-series forecasting fable

Time series forecasting is a fundamental skill for anyone working with temporal data. The fable package provides a tidy interface for forecasting, built on the principles of the tidyverse. This guide walks you through the complete workflow from data preparation to model evaluation.

Why Fable?

The fable package is part of the tidyverts ecosystem, which includes tsibble for time series data structures and fabletools for modelling. What makes fable stand out is its consistent API that feels familiar if you’ve used dplyr before. You pipe data through model specifications and forecasting functions without jumping between different syntaxes.

Installation and Setup

First, install the required packages from CRAN:

install.packages("fable")
install.packages("fabletools")
install.packages("tsibble")
install.packages("lubridate")

Load the libraries:

library(fable)
library(fabletools)
library(tsibble)
library(lubridate)
library(dplyr)
library(ggplot2)

Preparing Time Series Data

The fable ecosystem works with tsibble objects - tidy time series that extend tibbles with an index variable. Here’s how to convert your data:

# Create a tsibble from a data frame
my_tsibble <- my_data %>%
  as_tsibble(index = date_col)

# Or create from scratch for examples
sample_data <- tibble(
  date = seq(as.Date("2020-01-01"), by = "month", length.out = 36),
  value = cumsum(rnorm(36, mean = 2, sd = 1))
) %>% 
  as_tsibble(index = date)

The key requirement is having a properly defined index column that represents time. Tsibble handles various frequency types automatically, but you can specify it explicitly if needed.

Fitting Forecasting Models

Fable provides several model families. Here are the most common approaches:

Exponential Smoothing (ETS)

Exponential smoothing methods are popular for their simplicity and effectiveness. The ETS model automatically selects error, trend, and seasonality components:

ets_model <- sample_data %>%
  model(ets = ETS(value ~ trend("A") + season("M")))

ets_model

The formula specifies additive trend and multiplicative seasonality. Other options include “Ad” for additive damped trend, “M” for multiplicative error, and “N” for none.

ARIMA

Auto-Regressive Integrated Moving Average models capture autocorrelation patterns. Fable’s ARIMA function automatically selects the best parameters:

arima_model <- sample_data %>%
  model(arima = ARIMA(value))

arima_model

You can also specify ARIMA orders manually if you have domain knowledge about your data.

Prophet (via fable.prophet)

For data with strong seasonal patterns and holiday effects, Facebook’s Prophet model is excellent:

# Install if needed: install.packages("fable.prophet")
library(fable.prophet)

prophet_model <- sample_data %>%
  model(prophet = prophet(value ~ season("yearly")))

Generating Forecasts

Once you have a fitted model, generate forecasts with the forecast() function:

# Forecast 12 periods ahead
forecast_ets <- ets_model %>%
  forecast(h = "12 months")

forecast_arima <- arima_model %>%
  forecast(h = 12)

# View the forecasts
forecast_ets %>%
  autoplot(sample_data)

The h argument accepts various specifications including “12 months”, 12 (meaning 12 periods based on your data frequency), or “2 years”.

Model Evaluation

Cross-validation is essential for reliable forecasts. Use stretch_tsibble() to create expanding training windows:

# Time series cross-validation
cv_results <- sample_data %>%
  stretch_tsibble(.init = 12, .step = 1) %>%
  model(ets = ETS(value ~ trend("A"))) %>%
  forecast(h = 1)

# Calculate accuracy metrics
accuracy <- cv_results %>%
  accuracy(sample_data, by = ".id")

accuracy %>% 
  summarise(
    mae = mean(MAE),
    rmse = mean(RMSE),
    mape = mean(MAPE)
  )

This creates 24 different training sets starting with 12 observations, fitting a model to each, and forecasting one step ahead.

Working with Multiple Models

Compare models easily by fitting multiple specifications at once:

# Fit multiple models at once
comparison <- sample_data %>%
  model(
    ets = ETS(value ~ trend("A")),
    arima = ARIMA(value),
    naive = NAIVE(value),
    drift = RW(value ~ drift())
  )

# Compare forecasts
comparison %>%
  forecast(h = "12 months") %>%
  autoplot(sample_data)

This lets you visually compare how different approaches perform on your specific data.

Practical Example: Retail Sales

Putting it all together with a realistic example:

# Example with realistic data structure
retail_data <- tsibble(
  month = seq(as.Date("2018-01-01"), by = "month", length.out = 36),
  sales = cumsum(rnorm(36, 100, 20)) + 500
)

# Fit model and forecast
retail_model <- retail_data %>%
  model(ets = ETS(sales ~ trend("Ad") + season("M")))

retail_forecast <- retail_model %>%
  forecast(h = 12)

# Visualize with prediction intervals
retail_forecast %>%
  autoplot(retail_data) +
  labs(title = "Sales Forecast", y = "Sales ($)")

The autoplot function automatically shows prediction intervals, which are crucial for understanding forecast uncertainty.

Best Practices

When working with fable, keep these tips in mind:

  1. Check your data frequency - Use is_weekly(), is_monthly() to verify your tsibble is properly indexed
  2. Start simple - Try naive forecasts first as a baseline before complex models
  3. Validate properly - Use time series cross-validation, not random splits
  4. Check residuals - Always examine model residuals for patterns that your model missed

See Also