Neural Panel
NeuralPanelForecaster is the neural panel forecaster for direct
multi-horizon forecasts across related series. It uses ForecastFrame rows
with (series_id, timestamp, target, covariates), learns from train-only
normalized windows, and keeps panel series isolated while sharing the same
configured neural structure.
Use LaneNeuralPanelForecaster when series_id is a directional lane such as
source_id:target_id. The lane wrapper keeps 132:138 distinct from
138:132, appends origin/destination/lane embedding features plus directional
graph summary features into the training frame, and can forecast requested
cold lane ids through predict_for_lanes().
In the interactive forecast example, extra_regressors, events, and
holidays flow into the same neural-panel feature contract, so known future
covariates stay part of the forecast input.
Interactive Example
Runs neural_panel against a bundled route-demand sample.
Ready to run in this page.
The embedded example runs locally. Use it as a quick syntax and shape check,
not as quality evidence. Quality claims still need the maintained split
benchmark against seasonal naive and CartoBoostLagForecaster.
When To Use
Use this model when the hypothesis needs:
- direct multi-horizon panel forecasts rather than recursive local forecasts;
- fitted target-lag state through AR-Net with
n_lags; - future-known regressors, lagged regressors, event offsets, conditional seasonalities, or Fourier terms;
- global, local, or glocal trend, seasonality, event, and regressor behavior by series id;
- quantile output with non-crossing repair;
- directional lane ids and explicit cold-lane fallback.
Prefer CartoBoostLagForecaster when tabular lag features and tree splits are
the main signal. Prefer local models such as theta, ETS, ARIMA, Kalman, or
piecewise linear seasonal forecasting when one series needs an inspectable
statistical baseline.
Model Math
Training builds leakage-safe windows from each regular ForecastFrame series.
Each window contains normalized time for n_lags + n_forecasts, target lags
with shape B x n_lags, lagged covariate histories by configured name, and
future component features over the full lag-plus-horizon span. Target scaling is
fit only on the training frame.
The forward path is:
- compute the global trend and optional local per-series trend deviations;
- evaluate Fourier seasonality, event offsets, holidays encoded as events, and future regressors as additive or multiplicative nonstationary components;
- stationarize lagged targets against train-fit trend and component state;
- run AR-Net on stationarized target lags and Covar-Net on concatenated lagged regressor histories;
- add direct horizon stationary network output to the nonstationary forecast;
- map the median-first internal quantile layout back to requested quantile levels and repair crossings around the median output.
AR-Net and Covar-Net use deterministic Kaiming-style initialization, ReLU
hidden layers from ar_layers and lagged_reg_layers, and an output width of
n_forecasts * len(quantiles). Training uses an AdamW-style update loop. The
default loss is SmoothL1; loss="mse", loss="mae", and loss="pinball" are
also accepted. Set newer_sample_weight=True to use a monotone cosine recency
ramp.
Quantile heads use a median-first internal layout: the median residual lives at index 0 for each horizon, and non-median quantiles use learned positive or negative residual offsets. Public quantile tensors remain ordered by requested quantile level after crossing repair.
When future_regressors are configured, prediction requires known-future
covariates through model.predict(horizon, known_future=future_frame), unless
the regressor was proven constant per fitted series and stored as static future
state. Missing required dynamic future values hard-fail instead of silently
dropping the regressor.
LaneNeuralPanelForecaster generates static covariates named
lane_origin_embedding_*, lane_destination_embedding_*, lane_embedding_*,
and lane_graph_*. These generated covariates are added to the inner neural
panel as additive future regressors, so fitted nonstationary feature weights
learn from lane identity and directional graph summaries.
holidays and country_holidays are also accepted on the Python wrapper. When
you fit with a ForecastFrame, CartoBoost injects those holiday indicators as
known-future covariates so the native neural panel can train on them directly.
Use make_future_dataframe(frame, periods) to build the future scaffold and
reuse the same holiday injection logic for forecast-time frames.
You can also add regressors and events after construction with
add_seasonality(), add_future_regressor(), add_lagged_regressor(),
add_events(), and add_country_holidays(). For forecast inspection, use
components_json() or the browser includeComponents option to get a horizon
breakdown of trend, feature, AR, and lagged-regressor contributions. Use
history_components_json() or browser includeHistoryComponents to inspect
the fitted training rows.
Custom seasonalities can be gated with a condition_name covariate. When the
condition is false, the Fourier term is masked to zero at both fit and
prediction time. When the condition is constant per series, CartoBoost stores
it as static future state so prediction can proceed without a separate future
frame.
Use seasonality_global_local, event_global_local, and
regressor_global_local to choose global, local, or glocal parameter
sharing independently for Fourier terms, event offsets, and future regressors.
Backend Choice
CPU is the default backend for ordinary runs. On Apple-platform wheels built with the
native Metal feature, backend="metal" routes AR-Net and Covar-Net dense
prediction layers through CartoBoost's shared Metal backend. On Linux or WSL
wheels built with ROCm support, backend="rocm" routes the same dense
prediction layers through CartoBoost's shared HIP backend. On Windows or Linux
wheels built with CUDA support, backend="cuda" routes the same dense
prediction layers through CartoBoost's shared CUDA backend. Training updates and nonstationary feature
construction remain deterministic Rust code. Requested accelerators that are
not available in the installed build fail clearly instead of silently changing
the run contract.
Python Example
from cartoboost.forecasting import ForecastFrame, LaneNeuralPanelForecaster
frame = ForecastFrame.from_pandas(
hourly_lane_demand,
timestamp_col="pickup_hour",
target_col="pickup_trips",
series_id_col="pickup_dropoff_lane",
freq="h",
known_future_covariates=["is_airport_event"],
historical_covariates=["avg_trip_distance"],
)
future_frame = ForecastFrame.from_pandas(
future_hourly_lane_events,
timestamp_col="pickup_hour",
target_col="pickup_trips",
series_id_col="pickup_dropoff_lane",
freq="h",
known_future_covariates=["is_airport_event"],
)
model = LaneNeuralPanelForecaster(
n_lags=24,
n_forecasts=6,
quantiles=[0.1, 0.5, 0.9],
weekly_fourier_order=3,
future_regressors={"is_airport_event": "additive"},
lagged_regressors={"avg_trip_distance": 24},
ar_layers=[32],
lagged_reg_layers=[16],
trend_mode="glocal",
seasonality_global_local="glocal",
event_global_local="global",
regressor_global_local="glocal",
local_l2=0.1,
loss="smooth_l1",
epochs=80,
learning_rate=0.01,
weight_decay=0.001,
newer_sample_weight=True,
backend="cpu",
seed=42,
)
model.fit(frame)
forecast = model.predict(6, known_future=future_frame)
cold_lane_forecast = model.predict_for_lanes(6, ["132:138", "132:999"])
Do not use this model when only a handful of observations exist per lane, when future-known regressors are unavailable at forecast time, or when the main need is an easily audited local statistical baseline.
Validation
Validate neural panel forecasts with rolling-origin splits and the same
baselines used for the rest of the forecasting family. At minimum, compare
against seasonal naive and CartoBoostLagForecaster; for directional lane
work, include split views for ordinary rolling-origin lanes, cold lanes, cold
origins, and sparse-tail lanes when those cases matter for the claim.
Report RMSE, MAE, WAPE, horizon metrics, quantile diagnostics when quantiles are enabled, train time, prediction time, model settings, sample size, split boundaries, and whether the data is real or generated acceptance data.
The maintained benchmark entry point can emit the neural panel split artifact:
uv run --group dev python scripts/forecasting_library_benchmark.py \
--source polars \
--model-roster neural-panel \
--neural-panel-splits \
--lanes 36 \
--days 180 \
--horizon 14 \
--suite-folds 1 \
--output target/neural_panel_taxi_lane_split_suite.json
The JSON artifact records the command, split definitions, model settings, RMSE/MAE/WAPE metrics, timing, resource usage, and output path for rolling-origin, cold-lane, cold-origin, and sparse-tail checks.
Limitations
- Neural panel models need enough synchronized history and repeated entities to learn stable embeddings.
- Cold lanes and origins cannot use learned identity effects like repeated entities.
- Report accelerator availability and seed sensitivity with performance results.
- Missing or irregular panel rows require explicit preprocessing.