Extending the Theta forecasting method to GLMs and attention

R-bloggers 2025-04-09

[This article was first published on T. Moudiki's Webpage - R, and kindly contributed to R-bloggers]. (You can report issue about the content on this page here)
Want to share your content on R-bloggers? click here if you have a blog, or here if you don't.

In the new version (v0.18.0) of the ahead package, I have extended the forecast::thetaf function to support Generalized Linear Models (GLMs) and added an attention mechanism.

Attention is widely used in current neural networks (because they tend to forget; blame it on the gradients 🙂 ) to focus on specific parts of the input data when making predictions.

In this case, it helps the model to learn which parts of the time series are more important for forecasting, by using weighted averages of the past observations.

More on this later in a paper. A link to a notebook containing Python and R examples is provided at the end of this post.

1 – R version

Start with:

options(repos = c(    techtonique = "https://r-packages.techtonique.net",    CRAN = "https://cloud.r-project.org"))install.packages("ahead")

1 – 1 – USAccDeaths

library(forecast)library(ahead)# glm.nbpar(mfrow=c(2,1))obj1 <- suppressWarnings(ahead::glmthetaf(USAccDeaths, h=25L, fit_func=MASS::glm.nb, attention = TRUE, type_pi = "conformal-split", method = "adj"))plot(obj1, main="With attention")obj2 <- suppressWarnings(ahead::glmthetaf(USAccDeaths, h=25L, fit_func=MASS::glm.nb, attention = FALSE, type_pi = "conformal-split", method = "adj"))plot(obj2, main="Without attention")# glmpar(mfrow=c(2,1))obj1 <- suppressWarnings(ahead::glmthetaf(USAccDeaths, h=25L, fit_func=stats::glm, attention = TRUE, type_pi = "conformal-split", method = "adj"))plot(obj1, main="With attention")obj2 <- suppressWarnings(ahead::glmthetaf(USAccDeaths, h=25L, fit_func=stats::glm, attention = FALSE, type_pi = "conformal-split", method = "adj"))plot(obj2, main="Without attention")# rlmpar(mfrow=c(2,1))obj1 <- suppressWarnings(ahead::glmthetaf(USAccDeaths, h=25L, fit_func=MASS::rlm, attention = TRUE, type_pi = "conformal-split", method = "adj"))plot(obj1, main="With attention")obj2 <- suppressWarnings(ahead::glmthetaf(USAccDeaths, h=25L, fit_func=MASS::rlm, attention = FALSE, type_pi = "conformal-split", method = "adj"))plot(obj2, main="Without attention")# lqspar(mfrow=c(2,1))obj1 <- suppressWarnings(ahead::glmthetaf(USAccDeaths, h=25L, fit_func=MASS::lqs, attention = TRUE, type_pi = "conformal-split", method = "adj"))plot(obj1, main="With attention")obj2 <- suppressWarnings(ahead::glmthetaf(USAccDeaths, h=25L, fit_func=MASS::lqs, attention = FALSE, type_pi = "conformal-split", method = "adj"))plot(obj2, main="Without attention")# lmpar(mfrow=c(2,1))obj1 <- suppressWarnings(ahead::glmthetaf(USAccDeaths, h=25L, fit_func=stats::lm, attention = TRUE, type_pi = "conformal-split", method = "adj"))plot(obj1, main="With attention")obj2 <- suppressWarnings(ahead::glmthetaf(USAccDeaths, h=25L, fit_func=stats::lm, attention = FALSE, type_pi = "conformal-split", method = "adj"))plot(obj2, main="Without attention")# gampar(mfrow=c(2,1))obj1 <- suppressWarnings(ahead::glmthetaf(USAccDeaths, h=25L, fit_func=gam::gam, attention = TRUE, type_pi = "conformal-split", method = "adj"))plot(obj1, main="With attention")obj2 <- suppressWarnings(ahead::glmthetaf(USAccDeaths, h=25L, fit_func=gam::gam, attention = FALSE, type_pi = "conformal-split", method = "adj"))plot(obj2, main="Without attention")# rqpar(mfrow=c(2,1))obj1 <- suppressWarnings(ahead::glmthetaf(USAccDeaths, h=25L, fit_func=quantreg::rq, attention = TRUE, type_pi = "conformal-split", method = "adj"))plot(obj1, main="With attention")obj2 <- suppressWarnings(ahead::glmthetaf(USAccDeaths, h=25L, fit_func=quantreg::rq, attention = FALSE, type_pi = "conformal-split", method = "adj"))plot(obj2, main="Without attention")

1 - 2 - AirPassengers

# glm.nbpar(mfrow=c(2,1))obj1 <- suppressWarnings(ahead::glmthetaf(AirPassengers, h=25L, fit_func=MASS::glm.nb, attention = TRUE, type_pi = "conformal-split", method = "adj"))plot(obj1, main="With attention")obj2 <- suppressWarnings(ahead::glmthetaf(AirPassengers, h=25L, fit_func=MASS::glm.nb, attention = FALSE, type_pi = "conformal-split", method = "adj"))plot(obj2, main="Without attention")# glmpar(mfrow=c(2,1))obj1 <- suppressWarnings(ahead::glmthetaf(AirPassengers, h=25L, fit_func=stats::glm, attention = TRUE, type_pi = "conformal-split", method = "adj"))plot(obj1, main="With attention")obj2 <- suppressWarnings(ahead::glmthetaf(AirPassengers, h=25L, fit_func=stats::glm, attention = FALSE, type_pi = "conformal-split", method = "adj"))plot(obj2, main="Without attention")# rlmpar(mfrow=c(2,1))obj1 <- suppressWarnings(ahead::glmthetaf(AirPassengers, h=25L, fit_func=MASS::rlm, attention = TRUE, type_pi = "conformal-split", method = "adj"))plot(obj1, main="With attention")obj2 <- suppressWarnings(ahead::glmthetaf(AirPassengers, h=25L, fit_func=MASS::rlm, attention = FALSE, type_pi = "conformal-split", method = "adj"))plot(obj2, main="Without attention")# lmpar(mfrow=c(2,1))obj1 <- suppressWarnings(ahead::glmthetaf(AirPassengers, h=25L, fit_func=stats::lm, attention = TRUE, type_pi = "conformal-split", method = "adj"))plot(obj1, main="With attention")obj2 <- suppressWarnings(ahead::glmthetaf(AirPassengers, h=25L, fit_func=stats::lm, attention = FALSE, type_pi = "conformal-split", method = "adj"))plot(obj2, main="Without attention")# lqspar(mfrow=c(2,1))obj1 <- suppressWarnings(ahead::glmthetaf(AirPassengers, h=25L, fit_func=MASS::lqs, attention = TRUE, type_pi = "conformal-split", method = "adj"))plot(obj1, main="With attention")obj2 <- suppressWarnings(ahead::glmthetaf(AirPassengers, h=25L, fit_func=MASS::lqs, attention = FALSE, type_pi = "conformal-split", method = "adj"))plot(obj2, main="Without attention")# gampar(mfrow=c(2,1))obj1 <- suppressWarnings(ahead::glmthetaf(AirPassengers, h=25L, fit_func=gam::gam, attention = TRUE, type_pi = "conformal-split", method = "adj"))plot(obj1, main="With attention")obj2 <- suppressWarnings(ahead::glmthetaf(AirPassengers, h=25L, fit_func=gam::gam, attention = FALSE, type_pi = "conformal-split", method = "adj"))plot(obj2, main="Without attention")# rqpar(mfrow=c(2,1))obj1 <- suppressWarnings(ahead::glmthetaf(AirPassengers, h=25L, fit_func=quantreg::rq, attention = TRUE, type_pi = "conformal-split", method = "adj"))plot(obj1, main="With attention")obj2 <- suppressWarnings(ahead::glmthetaf(AirPassengers, h=25L, fit_func=quantreg::rq, attention = FALSE, type_pi = "conformal-split", method = "adj"))plot(obj2, main="Without attention")

2 - Python version

from rpy2.robjects.packages import importrfrom rpy2.robjects import rimport rpy2.robjects as roimport numpy as npimport matplotlib.pyplot as pltfrom rpy2.robjects import pandas2ri# Import required R packagesahead = importr('ahead')mass = importr('MASS')base = importr('base')stats = importr('stats')# Get the data and fit the modelwith localconverter(ro.default_converter):    # Get AirPassengers data    data = r('USAccDeaths')    data = np.array(data)        # Fit the model    fit = r('''        suppressWarnings(            ahead::glmthetaf(                USAccDeaths,                 h=25L,                 fit_func=MASS::glm.nb,                 attention=TRUE,                 type_pi="conformal-split",                 method="adj"            )        )    ''')        # Extract predictions and intervals    forecasts = np.array(fit.rx2('mean'))    lower = np.array(fit.rx2('lower'))    upper = np.array(fit.rx2('upper'))# Create time indicestime_train = np.arange(len(data))time_test = np.arange(len(data), len(data) + len(forecasts))# Create the plotplt.figure(figsize=(12, 6))# Plot training dataplt.plot(time_train, data, 'b-', label='Observed', alpha=0.7)# Plot forecasts and prediction intervalsplt.plot(time_test, forecasts, 'r--', label='Forecast')plt.fill_between(time_test, lower, upper,                  color='r', alpha=0.2,                  label='95% Prediction Interval')# Customize the plotplt.title('USAccDeaths Forecast with Attention')plt.xlabel('Time')plt.ylabel('-')plt.legend()plt.grid(True, alpha=0.3)# Show the plotplt.tight_layout()plt.show()

image-title-here

Open In Colab

To leave a comment for the author, please follow the link and comment on their blog: T. Moudiki's Webpage - R.

R-bloggers.com offers daily e-mail updates about R news and tutorials about learning R and many other topics. Click here if you're looking to post or find an R/data-science job.
Want to share your content on R-bloggers? click here if you have a blog, or here if you don't.
Continue reading: Extending the Theta forecasting method to GLMs and attention