ahead (Time Series Forecasting with uncertainty quantification) gets a lot faster to install: most dependencies are now optional
R-bloggers 2026-09-09
Want to share your content on R-bloggers? click here if you have a blog, or here if you don't.
If you’ve used ahead before, you may remember install.packages("ahead")or pip install ahead taking a while, since it dragged in two dozenmodeling packages up front regardless of which one you actually planned touse. That’s fixed now.
The problem: one function’s dependency, everyone’s install time
ahead supports a lot of forecasting methods, and each one can lean on adifferent modeling package: forecast, randomForest, e1071, glmnet,gam, quantreg, vars, fGarch, VineCopula, mboost, ranger,ForecastComb. Historically, most of these were plain Importsin DESCRIPTION, which means R installs all of them before you can evenload the package — regardless of whether you plan to use ahead::dynrmf with arandom forest or ahead::ridge2f for a multivariate model with none of the above.
The fix: (almost) everything becomes a Suggests
The new DESCRIPTION keeps only what the package’s core code actuallyneeds at load time:
Imports: Rcpp (>= 1.0.6), foreach, tseriesDepends: R (>= 3.5.0)Suggests: caret, cclust, dfoptim, doSNOW, doParallel, knitr, rmarkdown, testthat, fpp2, glmnet, e1071, gam, quantreg, randomForest, spatial, vars, roxygen2, ForecastComb, ranger, mboost, misc, Mcomp, fGarch, VineCopula, forecast (>= 8.0), ggplot2 (>= 3.0.0), randtoolbox (>= 1.17), simulatetimeseries
Everything else — randomForest, e1071, forecast, glmnet, vars,fGarch, VineCopula, and the rest — moved to Suggests. That means Rinstalls in seconds, because Rcpp, foreach, and tseries are the onlyhard requirements.
Installing the missing piece, exactly when you need it
Moving packages to Suggests only helps if the package still workssmoothly when you actually call a function that needs one of them. That’swhat a small internal helper, check_suggested(), takes care of:
check_suggested <- function(pkg, ask = interactive()) { if (requireNamespace(pkg, quietly = TRUE)) { return(invisible(TRUE)) } do_install <- TRUE if (ask) { do_install <- utils::askYesNo( sprintf("Package '%s' is required but not installed. Install it now?", pkg) ) do_install <- isTRUE(do_install) } if (do_install) { utils::install.packages( pkg, repos = c("https://techtonique.r-universe.dev", "https://cloud.r-project.org") ) } if (!requireNamespace(pkg, quietly = TRUE)) { stop( sprintf( "Package '%s' is required. Install it with install.packages('%s', repos = c('https://techtonique.r-universe.dev', 'https://cloud.r-project.org')).", pkg, pkg ), call. = FALSE ) } invisible(TRUE)}Every function (hopefully all of them!) that relies on a suggested package now callscheck_suggested("that_package") first. In practice, this means:
- If the package is already installed, nothing changes — no prompt, nodelay.
- If it’s missing and you’re in an interactive session, you get askedbefore anything is installed on your behalf.
- If it’s missing and the session isn’t interactive (a script, a CI job),it installs automatically.
- If the install still fails, you get a clear error with the exact commandto run, pointing at both CRAN and Techtonique’s r-universe repository —useful since a couple of these dependencies (like
ForecastCombandmisc) aren’t on CRAN at all.
So install.packages("ahead") is fast, and the first time you calldynrmf(..., fit_func = randomForest::randomForest), randomForest getsinstalled for you, once, and never again after that.
Same idea, carried into the Python wrapper
ahead’s Python package is a wrapper around the R package (via rpy2), sothe first call to any forecaster has always installed R-side dependencieson demand — that’s the “might take some time, but ONLY the 1st time it’scalled” comment you’ll see next to DynamicRegressor or Ridge2Regressorin the examples. With the R package’s own install now lean, that first-calloverhead on the Python side shrinks too: there’s less to pull in beforecheck_suggested() even gets to the package your chosen method needs.
import osimport numpy as npimport pandas as pdfrom ahead import DynamicRegressor, EATfrom time import time# Forecasting horizonh = 25# Data frame containing the time seriesdf = pd.read_csv("https://raw.githubusercontent.com/Techtonique/datasets/refs/heads/main/time_series/univariate/AirPassengers.csv").set_index('date')df.index = pd.DatetimeIndex(df.index)print(df)# univariate ts forecastingprint("Example 1 -----")d1 = DynamicRegressor(h=h, date_formatting="ms")print(d1.__module__)start = time()d1.forecast(df)print(f"Elapsed: {time()-start} \n")print("averages: \n")print(d1.averages_)print("\n")print("ranges: \n")print(d1.ranges_)print("\n")print("Example 2 -----")d2 = DynamicRegressor(h=h, type_pi="T", date_formatting="original")start = time()d2.forecast(df)print(f"Elapsed: {time()-start} \n")print("averages: \n")print(d2.averages_)print("\n")print("ranges: \n")print(d2.ranges_)print("\n")d2.plot()The first call to DynamicRegressor.forecast() in a fresh environment isthe one that pays the (now much smaller) one-time cost of installing the Rahead package; every call after that — including d2 above, in the samesession — runs at full speed.
Why this matters in practice
-
Faster CI and Docker builds — you’re not compiling
gam,fGarch,VineCopula, and a dozen others just to run a couple of unit tests thatuse two of them. -
Less fragile installs — a slow-to-compile or awkward-to-build modelingpackage no longer stands between you and a working
aheadinstall if youdon’t even need that method. -
Smaller footprint for the methods you actually use — if you only evercall
ridge2f, you never install the GARCH or copula-based dependenciesat all.
If you want everything available up front (for example, to prepare anoffline environment), you can still install every suggested packageyourself:
install.packages( c("caret", "cclust", "dfoptim", "doSNOW", "doParallel", "fpp2", "glmnet", "e1071", "gam", "quantreg", "randomForest", "spatial", "vars", "ranger", "mboost", "Mcomp", "fGarch", "VineCopula", "forecast", "ggplot2", "randtoolbox", "simulatetimeseries"), repos = c("https://techtonique.r-universe.dev", "https://cloud.r-project.org"))Get it
- R: see the README for the Techtonique repo setup, version
0.38.1. - Python:
pip install ahead --verbose, from ahead_python.
As always, issues and contributions are welcome on both repos.

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.