machine learning
vector autoregression
time series analysis
scikit-learn
predictive modeling

Vector autoregressive model fitting with scikit-learn

ML System Design practice on Codemia

Design recommenders, ranking systems and training pipelines the way ML interviews actually ask for them, with worked solutions.

Practice ML system design

Introduction

A vector autoregressive model predicts several time series together by using previous values from all series as inputs. Scikit-learn does not ship a dedicated VAR class, but you can model the same idea by converting lagged history into a supervised learning matrix. This pattern is useful when you want scikit-learn pipelines, model selection APIs, and deployment-friendly estimators. This approach is especially useful when you want one scikit-learn deployment path for both classical regression baselines and richer ensemble models.

Reframe VAR as a Multi-Output Regression Problem

For a VAR of lag order p, each training row uses p previous time steps and predicts the current step. If there are k variables, each feature row has p * k values, and each target row has k values.

python
1import numpy as np
2
3
4def make_var_dataset(y: np.ndarray, lag: int):
5    X, Y = [], []
6    for t in range(lag, len(y)):
7        X.append(y[t - lag:t].reshape(-1))
8        Y.append(y[t])
9    return np.asarray(X), np.asarray(Y)
10
11
12series = np.array([
13    [10.0, 100.0],
14    [11.0, 101.0],
15    [13.0, 100.5],
16    [12.0, 102.0],
17    [14.0, 103.0],
18    [15.0, 104.0],
19    [16.0, 105.0],
20])
21
22X, Y = make_var_dataset(series, lag=2)
23print(X.shape, Y.shape)

This transformation is the core step. The rest of the workflow looks like a normal supervised learning project.

Start with a Linear Baseline

Classical VAR is linear, so linear regression or ridge regression is a strong baseline.

python
1from sklearn.linear_model import Ridge
2from sklearn.metrics import mean_absolute_error
3
4split = int(len(X) * 0.8)
5X_train, X_test = X[:split], X[split:]
6Y_train, Y_test = Y[:split], Y[split:]
7
8model = Ridge(alpha=1.0)
9model.fit(X_train, Y_train)
10
11pred = model.predict(X_test)
12print("MAE total:", mean_absolute_error(Y_test, pred))
13print("MAE var0:", mean_absolute_error(Y_test[:, 0], pred[:, 0]))
14print("MAE var1:", mean_absolute_error(Y_test[:, 1], pred[:, 1]))

Always report per-variable error, not only one aggregate number. One target can degrade while overall error still looks acceptable.

Use Time-Aware Validation

Random shuffle splits leak temporal structure. Use chronological splits or walk-forward validation.

python
1from sklearn.model_selection import TimeSeriesSplit
2from sklearn.base import clone
3
4cv = TimeSeriesSplit(n_splits=4)
5base = Ridge(alpha=0.5)
6
7fold_mae = []
8for train_idx, val_idx in cv.split(X):
9    m = clone(base)
10    m.fit(X[train_idx], Y[train_idx])
11    p = m.predict(X[val_idx])
12    fold_mae.append(mean_absolute_error(Y[val_idx], p))
13
14print("Fold MAE:", fold_mae)
15print("Mean MAE:", float(np.mean(fold_mae)))

This gives a more realistic estimate of future forecasting behavior.

Add Nonlinear Models Carefully

If residuals show nonlinear structure, try tree-based or boosted models through multi-output wrappers.

python
1from sklearn.multioutput import MultiOutputRegressor
2from sklearn.ensemble import RandomForestRegressor
3
4rf = MultiOutputRegressor(
5    RandomForestRegressor(n_estimators=200, random_state=42)
6)
7rf.fit(X_train, Y_train)
8rf_pred = rf.predict(X_test)
9print("RF MAE:", mean_absolute_error(Y_test, rf_pred))

Nonlinear models can improve fit, but overfitting risk rises fast with small time-series datasets. Keep linear baseline as a reference point.

Multi-Step Forecasting Pattern

One-step-ahead prediction is easiest, but many applications need horizon forecasts. A standard approach is recursive forecasting where each predicted step becomes part of the next input window.

python
1def recursive_forecast(model, last_window, steps, n_vars):
2    window = last_window.copy()  # shape: (lag, n_vars)
3    out = []
4    for _ in range(steps):
5        x = window.reshape(1, -1)
6        yhat = model.predict(x)[0]
7        out.append(yhat)
8        window = np.vstack([window[1:], yhat])
9    return np.asarray(out)
10
11future = recursive_forecast(model, series[-2:], steps=3, n_vars=2)
12print(future)

Track error by forecast horizon because accuracy usually drops as horizon grows.

Feature Engineering That Helps VAR-Style Models

Useful additions include:

  • seasonal lags, such as 24 for hourly data
  • differences or percent changes to stabilize trend
  • calendar features such as day index
  • exogenous regressors such as promotions or weather

When adding engineered features, ensure the same feature generation logic runs during training and inference.

Common Pitfalls

A common mistake is leakage from future values when constructing lag windows. Build features from strictly earlier timestamps only.

Another issue is random cross-validation on temporal data. This inflates metrics and leads to disappointing production performance.

A third issue is tuning complex models before validating a linear baseline. Many datasets are well explained by simple lagged linear structure.

Teams also forget to evaluate each target separately. Multi-output metrics can hide weak performance on the variable that matters most to the business.

Summary

  • VAR can be implemented in scikit-learn by reframing sequence history as supervised multi-output regression.
  • Lag feature construction is the essential step and must avoid time leakage.
  • Use chronological validation or walk-forward folds, never random shuffle splits.
  • Keep a linear baseline and add nonlinear estimators only when residual patterns justify it.
  • Evaluate one-step and multi-step behavior separately, with per-target error reporting.

Related reading
Free course
Beginner
7 lessons
2 hours
Tackling System Design Interview Problems

A short course that equips you with the skills to approach system design interviews methodically.

Start the free course
Track what you have practised

A free account saves your progress, solutions and study plan across every problem on Codemia.

ML System Design practice on Codemia

Design recommenders, ranking systems and training pipelines the way ML interviews actually ask for them, with worked solutions.

Practice ML system design

All Rights Reserved.