Skip to content

Add exogenous forecasting models (ARIMAX, SARIMAX, and linear regression) - #862

Open
Irozuku wants to merge 2 commits into
feat/exogenous-forecasting-taskfrom
feat/exogenous-forecasting-models
Open

Add exogenous forecasting models (ARIMAX, SARIMAX, and linear regression)#862
Irozuku wants to merge 2 commits into
feat/exogenous-forecasting-taskfrom
feat/exogenous-forecasting-models

Conversation

@Irozuku

@Irozuku Irozuku commented Sep 4, 2026

Copy link
Copy Markdown
Collaborator

Summary

ExogenousForecastingTask had no models to run. ForecastingModel now reads the numeric columns beside the date as explanatory variables when the model declares SUPPORTS_EXOGENOUS.

Three models serve the new task, and the split between them is the point:

Model Reads a date alone Needs variables Tasks
ARIMA yes no both
SARIMAX (new) yes no both
ExogenousLinearRegression (new) no yes exogenous only
NaiveForecaster, SeasonalNaiveForecaster, ExponentialSmoothing yes cannot use them plain only

ARIMA gains an exog term, so with a date alone it is the plain ARIMA it was, and with variables beside it an ARIMA with regressors. SARIMAX adds the seasonal orders ARIMA does not expose, and is likewise optional in both. ExogenousLinearRegression fits the series as a straight line in the variables with no memory of its own history, which is what makes it worth comparing against the other two: a large gap between their scores says whether the series is driven by its own momentum or by something outside it.


Type of Change

Check all that apply like this [x]:

  • Backend change
  • Frontend change
  • CI / Workflow change
  • Build / Packaging change
  • Bug fix
  • Documentation

Changes (by file)

  • DashAI/back/models/forecasting/base_forecasting_model.py: added SUPPORTS_EXOGENOUS, _remember_exogenous, _exogenous_of and _exogenous_over. _forecast_at no longer takes a callable and passes the exogenous matrix when the model was fitted with variables. _forecast gained an optional exog argument. COMPATIBLE_COMPONENTS was removed from this class, see Notes.
  • DashAI/back/models/forecasting/arima.py: fits and forecasts with exog. Declares both tasks and SUPPORTS_EXOGENOUS.
  • DashAI/back/models/forecasting/sarimax.py: new. Seven orders (p, d, q, P, D, Q, season length), the seasonal part disabled at a season length below 2. Refuses a season the series is too short to show twice. Declares both tasks.
  • DashAI/back/models/forecasting/exogenous_linear_regression.py: new. Ridge on the variables, with an optional period number trend so a drift the variables do not account for can still be fitted. Refuses a date column with nothing beside it. Declares the exogenous task alone.
  • DashAI/back/models/forecasting/naive.py, seasonal_naive.py, exponential_smoothing.py: each now declares COMPATIBLE_COMPONENTS = ["ForecastingTask"] for itself.
  • DashAI/back/initial_components.py: registers SARIMAX and ExogenousLinearRegression.
  • tests/back/models/test_exogenous_forecasting_models.py: new. Covers which tasks each model declares, one value per requested row, the variables actually changing the forecast, a forecast far past the training data, a missing variable being refused, save/load round trips, the dual models still working from a date alone, the linear model recovering a known linear relationship, and the SARIMAX seasonal guards.

Testing

  • Plain forecasting regression: Train ARIMA, Naive, Seasonal Naive and Exponential Smoothing on Forecasting using only date as input. ARIMA scores should match develop, and all models should train successfully.

  • Task/model compatibility: Verify Forecasting offers ARIMA, SARIMAX, Naive, Seasonal Naive and Exponential Smoothing, but not Exogenous Linear Regression. Verify Forecasting with Exogenous Variables offers only ARIMA, SARIMAX and Exogenous Linear Regression.

  • Input validation: On Forecasting with Exogenous Variables, verify date + exg_1 is accepted, date alone and exg_1 alone are rejected, multiple date columns are rejected, and column order does not matter.

  • Training and prediction: Train ARIMA, SARIMAX and Exogenous Linear Regression with date + exg_1 + exg_2. Verify Temporal Holdout/Rolling Origin are the only available splitters, metrics produce values, and future predictions respond to changes in the exogenous variables. Missing variables and dates inside the training window must be rejected.


Notes

Exogenous variables are used contemporaneously:

y[t] = b * x[t] + n[t]

The models do not automatically use x[t-1], x[t-2], etc. Future forecasts therefore require the exogenous values for the requested forecast rows.

Intermediate exogenous rows may be interpolated when the forecast horizon contains gaps. These values do not affect the requested forecast rows, as verified by regression tests.

Lagged exogenous variables are out of scope and would require extending the time series windowing/conversion pipeline.

ExogenousForecastingTask had no models to run. ForecastingModel now
reads the numeric columns beside the date as explanatory variables when
the model declares SUPPORTS_EXOGENOUS, and lays them out over the whole
horizon being forecast: the requested rows can start a validation window
past the training data, and the periods in between are interpolated,
the same bargain the forecast itself makes across such a gap.

ARIMA gains an exog term, so with a date alone it is the plain ARIMA it
was and with variables beside it an ARIMA with regressors. SARIMAX adds
the seasonal orders ARIMA does not expose, and is likewise optional in
both. Both therefore serve either task. ExogenousLinearRegression fits
the series as a straight line in the variables with no memory of its own
history, which is what makes it worth comparing against the other two;
it needs variables, so it serves the exogenous task alone.

Each model now names the tasks it serves instead of inheriting the list
from ForecastingModel, which would otherwise offer a model that needs
variables for the task that has none.
The docstring claimed the interpolated rows were the same bargain the
point forecast makes across a gap, with error compounding through them.
They are not. statsmodels fits regression with ARIMA errors and
forecasts the error term from the training residuals alone, so a
requested step is built from its own exogenous row plus the history of
the series. The filled rows only produce the values at their own steps,
which are discarded.

Filling the gap flat, with zeros, or with -5000 gives identical
forecasts at the requested steps for all three models, which is now a
test.
@Irozuku Irozuku added the back Backend work label Sep 4, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

back Backend work

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant