Skip to main content
Open llms.txtCopy tools

Forecasting Benchmark

This page summarizes the maintained forecasting benchmark artifacts. Lower is better for RMSE, MAE, WAPE, WRMSSE, RPS, and mean RMSE ratio. A mean RMSE ratio of 1.000000 means the model tied the best RMSE observed on that artifact and split.

NYC Taxi Demand​

Real taxi demand uses January–April 2024 NYC TLC yellow taxi trips, 24 pickup/dropoff lanes, daily aggregation, and three leakage-safe rolling origins with a 7-day horizon. The maintained artifact compares CartoBoost with functime and external lag-tree baselines under the same protocol.

RankModelRMSEMAEWAPEArtifact
1functime_snaive77.69068848.0912700.169428forecasting_library_benchmark_real.json
2cartoboost_auto_forecast85.72645750.8680850.177963forecasting_library_benchmark_real.json
3cartoboost_lag88.66281750.0144660.174668forecasting_library_benchmark_real.json
4lightgbm_lag89.46295650.7952800.177978forecasting_library_benchmark_real.json
5xgboost_lag89.67044150.7228840.177666forecasting_library_benchmark_real.json
6functime_ridge100.66819867.9306660.237628forecasting_library_benchmark_real.json
7functime_lightgbm123.96616878.9586230.271460forecasting_library_benchmark_real.json

Read: cartoboost_auto_forecast is 4.18% lower RMSE than the strongest completed external learned baseline (lightgbm_lag) across the three rolling origins. It does not beat the seasonal-naive library baseline, so the artifact does not claim a win against every forecasting library. The external-baseline gate is recorded directly in the JSON artifact and passes the v0.3 within-5% RMSE rule. The current run loaded and aggregated 13,069,067 source rows in 2.050 seconds and completed in 22.379 seconds. It recorded 71.205 CPU-seconds and a 925 MiB peak resident set; per-fold fit and prediction timings remain in the JSON artifact.

Reproduce the maintained artifact with:

PYTHONPATH=python uv run --group dev --group bench python scripts/forecasting_library_benchmark.py \
--source nyc-taxi --year 2024 --months 1,2,3,4 --taxi-type yellow \
--lanes 24 --horizon 7 --rolling-origin-folds 3 --no-hyperopt \
--model-roster scalable --cartoboost-n-estimators 48 \
--cartoboost-auto-n-estimators 48 \
--no-download \
--output docs/assets/nyc_taxi_benchmarks/forecasting_library_benchmark_real.json \
--plot-dir docs/assets/nyc_taxi_benchmarks/forecasting_plots

Comparability audit for forecasting_library_benchmark_real.json: every requested model completed on the same three rolling-origin folds and 7-day horizon, uses the same metric set, and records candidate selection without outer test-label selection. The strongest completed external learned baseline is lightgbm_lag; CartoBoost's 0.958234 RMSE ratio versus that baseline is inside the five-percent acceptance gate. The seasonal-naive result remains reported as a separate, stronger forecasting-library reference.

Synthetic Demand Checks​

The synthetic demand artifacts keep taxi-shaped route-demand diagnostics in the benchmark suite. They are not real TLC data.

RunRankModelMean RMSE RatioWins/TiesArtifact
CartoBoost sample1cartoboost_auto_forecast1.0000004forecasting_overhaul_committed_suite.json
Scalable external roster1cartoboost_auto_forecast1.0137443forecasting_overhaul_committed_suite_scalable_roster.json
Scalable external roster3lightgbm_lag1.2792381forecasting_overhaul_committed_suite_scalable_roster.json
Generalization guardrail1cartoboost_auto_forecast1.0000004forecasting_generalization_scalable_synthetic.json
Generalization guardrail3lightgbm_lag1.1963960forecasting_generalization_scalable_synthetic.json
Generalization guardrail4xgboost_lag1.2588160forecasting_generalization_scalable_synthetic.json

Read: the current scalable synthetic checks favor CartoBoost.

Prophet-Compatible Surface​

cartoboost.Prophet provides the familiar ds/y workflow over the Rust piecewise-linear core. The façade accepts pandas or Polars input, creates future dataframes, supports Fourier seasonalities, extra regressors, holidays, intervals, component columns, and predictive-sample access, and returns Prophet-shaped ds, yhat, yhat_lower, and yhat_upper results.

The matched smoke benchmark uses the same deterministic daily fixture, weekly seasonality, 30-day horizon, and uncertainty_samples=0. Timings below are model timings after imports; the upstream Prophet run uses prophet==1.2.2 and converts Polars to pandas, while CartoBoost fits the Polars frame directly.

RowsEngineInputFit secondsPredict secondsTotal secondsOutput rows
500cartoboost.ProphetPolars0.01700.00520.022230
500prophet.ProphetPolars → pandas0.05380.00370.057530
100,000cartoboost.ProphetPolars0.23590.00980.245730
100,000prophet.ProphetPolars → pandas1.89200.00401.896030

CartoBoost is 2.6× faster on the 500-row run and 7.7× faster on the 100,000-row run under this single-series protocol. The optimized path avoids serializing historical component rows when the requested forecast is future-only; the native Rust forecast and component calls remain sub-10 ms on the 100,000-row case. These are synthetic performance results, not a quality claim; the functionality claim is covered by the pandas/Polars compatibility test and Prophet-shaped output contract.

Reproduce the rows independently in the two environments:

uv run --group dev python scripts/prophet_surface_benchmark.py --engine cartoboost --rows 500 --input polars
uv run --group dev python scripts/prophet_surface_benchmark.py --engine cartoboost --rows 100000 --input polars
/tmp/prophet-venv/bin/python scripts/prophet_surface_benchmark.py --engine prophet --rows 500 --input polars
/tmp/prophet-venv/bin/python scripts/prophet_surface_benchmark.py --engine prophet --rows 100000 --input polars

The public-method audit compares the 33-method Prophet 1.2.2 surface against the CartoBoost façade and reports missing methods and signatures as JSON:

/tmp/prophet-venv/bin/python scripts/prophet_parity_audit.py --engine prophet > /tmp/prophet-audit-upstream.json
uv run --group dev python scripts/prophet_parity_audit.py --engine cartoboost > /tmp/prophet-audit-cartoboost.json

Both engines report all 33 audited methods present. Numerical Stan posterior parity and MCMC backend parity remain outside this Rust-native deterministic surface; those modes are rejected explicitly by CartoBoost.

Intermittent Demand Checks​

The intermittent-demand suite exercises the fixed Croston, SBA, and TSB forecasters on four taxi-shaped synthetic problems with sparse zero-heavy series. It is a library-only roster, so there is no CartoBoost row in this run.

Rerun command:

PYTEST_DISABLE_PLUGIN_AUTOLOAD=1 uv run --no-sync --group dev --group bench python scripts/forecasting_library_benchmark.py \
--suite \
--source polars \
--days 120 \
--lanes 4 \
--horizon 7 \
--suite-folds 2 \
--model-roster intermittent \
--no-candidate-selection \
--no-hyperopt \
--output target/forecasting_intermittent_suite.json
RankModelMean RMSE RatioWins/TiesTop-3 Finishes
1croston1.00000044
2tsb1.00002004
3sba1.16376604

Per-problem RMSE:

Problemcrostonsbatsb
airport_calendar_events2.6283653.1283372.628444
borough_monthly_pulses3.0521333.4787713.052177
route_mix_shift2.7039333.1719212.703990
taxi_weekly2.7604853.1800322.760527

Read: Croston is the strongest fixed intermittent-demand baseline in this current synthetic taxi-shaped suite, with TSB effectively tied on RMSE and SBA consistently behind both. This is implementation evidence for the intermittent roster path, not a real-data taxi demand claim.

NeuralPanel Lane Split Suite​

NeuralPanelForecaster has a dedicated taxi-lane split suite for checking direct multi-horizon neural behavior under four panel stresses: rolling-origin, cold-lane, cold-origin, and sparse-tail. The roster is intentionally small: seasonal_naive, cartoboost_lag, and cartoboost_neural_panel.

Rerun command:

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 exact command, split definitions, RMSE/MAE/WAPE metrics, timing, model settings, resource usage, and artifact path. Cold identity splits expand missing-lane forecasts by exact lane when available, then origin, destination, and global horizon means. Treat the suite as implementation evidence until a maintained artifact is committed and summarized with its actual metric table.

CartoBoost Piecewise Local Diagnostics​

The piecewise roster runs only CartoBoost's cartoboost_piecewise_linear_seasonal model. This is the local Prophet-style tool for trend, changepoints, Fourier seasonality, events, regressors, fitted artifacts, and component decomposition, surfaced as piecewise_linear_seasonal in Python and the interactive docs examples.

This synthetic suite run uses four taxi-shaped daily demand problem families, 4 pickup/dropoff lanes per problem, 120 daily observations, two rolling-origin folds, and a 7-day horizon. Candidate selection and hyperparameter search are disabled so the plots show the local model behavior directly.

ProblemModelRMSEMAEWAPE
airport_calendar_eventscartoboost_piecewise_linear_seasonal1.5798930.8074650.035577
borough_monthly_pulsescartoboost_piecewise_linear_seasonal2.0590261.5176400.066407
route_mix_shiftcartoboost_piecewise_linear_seasonal0.6038900.4843080.021195
taxi_weeklycartoboost_piecewise_linear_seasonal1.3582771.1584680.050880

Read: on these deterministic synthetic Prophet-shaped tasks, the local CartoBoost piecewise model executes the trend, changepoint, and Fourier seasonality path without Stan while preserving the rolling-origin split protocol. This is synthetic evidence for the piecewise linear seasonal implementation path, not a replacement for real taxi or M-series forecasting evidence.

Rendered local CartoBoost piecewise diagnostics:

CartoBoost piecewise forecast lines for taxi weekly demand

CartoBoost piecewise horizon RMSE for airport calendar events

CartoBoost piecewise actual versus predicted for route mix shift

Rerun command:

PYTEST_DISABLE_PLUGIN_AUTOLOAD=1 uv run --no-sync --group dev --group bench python scripts/forecasting_library_benchmark.py \
--suite synthetic \
--source polars \
--days 120 \
--lanes 4 \
--horizon 7 \
--suite-folds 2 \
--model-roster piecewise \
--no-candidate-selection \
--no-hyperopt \
--cartoboost-n-estimators 5 \
--cartoboost-auto-n-estimators 5 \
--output target/forecasting_piecewise_local_suite.json \
--plot-dir docs/assets/nyc_taxi_benchmarks/piecewise_local_plots

Spatial Piecewise Kriging Diagnostic​

The deterministic spatial_piecewise_kriging_panel check exercises the Prophet-shaped CartoBoost base with ordinary kriging fusion. It uses 6 pickup/dropoff lanes, 180 daily observations per lane, a 7-day rolling-origin holdout, fixed model settings, and no hyperparameter search. The split rule is strictly time ordered: train timestamps end on 2024-06-21 and validation starts on 2024-06-22.

The roster includes Naive, SeasonalNaive, PiecewiseLinearSeasonal, KrigingForecaster, and spatial_piecewise_kriging_hybrid under the same split. The hybrid row uses zone_pressure as a known future spatial regressor and residual kriging over stable lane coordinates. The artifact also records fit time, prediction time, model metadata, cutoffs, variogram config, and RMSE/MAE / WAPE deltas against piecewise_linear_seasonal and seasonal_naive.

ModelRMSEMAEWAPEFit secondsPredict secondsRMSE delta vs piecewise
cartoboost_lag0.0457930.0383380.0006330.3533980.002575-1.989170
seasonal_naive0.9492910.8212930.0135610.0010320.001104-1.085673
spatial_piecewise_kriging_hybrid1.0165710.9024310.0149000.0507650.006882-1.018393
theta1.8499151.6614330.0274320.0028720.001364-0.185048
weighted_ensemble1.9104061.6901880.0279070.0036230.001746-0.124558
piecewise_linear_seasonal2.0349641.8432950.0304350.0090160.0021140.000000
optimized_theta2.1423221.7624960.0291010.0265230.0019790.107359
kriging2.2372211.8572570.0306660.0023410.0016850.202257
naive2.2372211.8572590.0306660.0010300.0012610.202258

Read: the hybrid improves RMSE, MAE, and WAPE versus the base piecewise_linear_seasonal row by using the kriged zone_pressure regressor and residual correction on this synthetic spatial residual task. It is not the best row overall: cartoboost_lag and seasonal_naive are stronger on this deterministic panel. Treat the run as implementation and leakage-check evidence for spatial fusion, not as a production taxi-demand quality claim.

Rerun command:

uv run --group dev python scripts/forecasting_benchmark.py \
--days 180 \
--horizon 7 \
--folds 1 \
--panel-series 6 \
--output target/spatial_piecewise_kriging_benchmark.json

The run above writes target/spatial_piecewise_kriging_benchmark.json.

M4 Sample​

The current M4 sample scores the first 96 series from each M4 frequency group. It is a sample, not a full M4 corpus result.

RankModelMean RMSE RatioWins/TiesTop-3 FinishesArtifact
1cartoboost_auto_forecast1.00000066forecasting_overhaul_m4_committed.json
2cartoboost_lag12.10457036forecasting_overhaul_m4_committed.json

Read: cartoboost_auto_forecast wins or ties all six M4 sample groups on this artifact.

M5 Demand Forecasting​

The M5 table reports current-code CartoBoost models against external baselines. The 100-series comparison uses the public M5 files and a full external roster. The full-corpus fast check covers all 30,490 bottom-level item-store series with the fast CartoBoost roster.

RunRankModelRMSEMAEWAPEWRMSSEArtifact
Sample1cartoboost_auto_forecast2.4152251.1392850.9106150.568942forecasting_overhaul_m5_committed.json
Sample2cartoboost_lag2.5406251.2199270.9750710.743721forecasting_overhaul_m5_committed.json
100-series comparison1cartoboost_auto_forecast2.5112921.1355850.9160590.669928forecasting_m5_full_roster_sample.json
100-series comparison2statsforecast_autoets2.5257341.1419990.9212320.717426forecasting_m5_full_roster_sample.json
100-series comparison3statsforecast_dynamic_optimized_theta2.5565171.1637500.9387790.712698forecasting_m5_full_roster_sample.json
100-series comparison4statsforecast_autotbats2.6020551.1565880.9330010.618397forecasting_m5_full_roster_sample.json
100-series comparison5functime_ridge2.6067751.2078780.9743760.711331forecasting_m5_full_roster_sample.json
100-series comparison6statsforecast_autotheta2.6070771.1960420.9648280.723187forecasting_m5_full_roster_sample.json
100-series comparison7statsforecast_autoarima2.6557541.1943120.9634330.739778forecasting_m5_full_roster_sample.json
100-series comparison8xgboost_lag2.7934771.5004461.2103861.249158forecasting_m5_full_roster_sample.json
100-series comparison9cartoboost_lag2.8055431.2857251.0371730.827678forecasting_m5_full_roster_sample.json
100-series comparison10statsforecast_autoces2.8180831.2280580.9906550.630302forecasting_m5_full_roster_sample.json
100-series comparison11lightgbm_lag2.8252951.2539911.0115751.000983forecasting_m5_full_roster_sample.json
100-series comparison12functime_snaive3.2862811.3375001.0789400.825078forecasting_m5_full_roster_sample.json
100-series comparison12statsforecast_seasonal_naive3.2862811.3375001.0789400.825078forecasting_m5_full_roster_sample.json
100-series comparison14functime_lightgbm3.3422141.3791771.1125600.982476forecasting_m5_full_roster_sample.json
100-series comparison15prophet_additive14.9609596.1467004.9584443.366280forecasting_m5_full_roster_sample.json
Full-corpus fast check1cartoboost_lag2.6348791.3329970.923884n/aforecasting_m5_full.json

Read: cartoboost_auto_forecast is first by RMSE on the sample and 100-series M5 comparison. AutoTBATS is first by WRMSSE on the 100-series comparison.

M6 Daily Returns​

The M6 artifacts are daily-return forecasting proxies with five-bucket rank probabilities. They are not official M6 submission files.

RunRankModelRMSEMAEWAPERPSArtifact
Sample1cartoboost_auto_forecast0.0134390.0073421.0000000.208171forecasting_overhaul_m6_committed.json
Sample2cartoboost_lag0.0144400.0092901.2653380.200754forecasting_overhaul_m6_committed.json
100-symbol comparison1cartoboost_auto_forecast0.0133920.0073571.0000000.206007forecasting_m6_full.json
100-symbol comparison2statsforecast_autoarima0.0134020.0074001.0058440.200029forecasting_m6_full.json
100-symbol comparison3statsforecast_autoets0.0134080.0074561.0135240.198295forecasting_m6_full.json
100-symbol comparison4functime_ridge0.0134740.0076701.0425530.198198forecasting_m6_full.json
100-symbol comparison5statsforecast_autotbats0.0134770.0076631.0415800.200969forecasting_m6_full.json
100-symbol comparison6statsforecast_autoces0.0135220.0076171.0352890.198260forecasting_m6_full.json
100-symbol comparison7statsforecast_dynamic_optimized_theta0.0136690.0082041.1151870.199984forecasting_m6_full.json
100-symbol comparison8statsforecast_autotheta0.0136830.0082281.1184620.197417forecasting_m6_full.json
100-symbol comparison9xgboost_lag0.0142460.0088961.2091600.199529forecasting_m6_full.json
100-symbol comparison10cartoboost_lag0.0143480.0093571.2718680.204266forecasting_m6_full.json
100-symbol comparison11lightgbm_lag0.0160870.0109551.4891350.200887forecasting_m6_full.json
100-symbol comparison12prophet_additive0.0174170.0117501.5970960.197646forecasting_m6_full.json
100-symbol comparison13functime_lightgbm0.0174740.0111631.5173490.198504forecasting_m6_full.json
100-symbol comparison14functime_snaive0.0178460.0107801.4653150.192195forecasting_m6_full.json
100-symbol comparison14statsforecast_seasonal_naive0.0178460.0107801.4653150.192195forecasting_m6_full.json

Read: cartoboost_auto_forecast is first by RMSE on the sample and 100-symbol M6 artifact. Seasonal-naive baselines are first by RPS on the 100-symbol comparison.

Reproduce​

uv run --group dev python scripts/forecasting_library_benchmark.py \
--source nyc-taxi \
--year 2024 \
--months 1,2,3,4 \
--taxi-type yellow \
--lanes 24 \
--horizon 7 \
--rolling-origin-folds 3 \
--no-download \
--no-hyperopt \
--model-roster scalable \
--cartoboost-n-estimators 48 \
--cartoboost-auto-n-estimators 48 \
--output docs/assets/nyc_taxi_benchmarks/forecasting_library_benchmark_real.json \
--plot-dir docs/assets/nyc_taxi_benchmarks/forecasting_plots

uv run --group dev python scripts/forecasting_library_benchmark.py \
--suite committed \
--no-hyperopt \
--model-roster cartoboost \
--no-candidate-selection \
--output docs/assets/nyc_taxi_benchmarks/forecasting_overhaul_committed_suite.json

uv run --group dev python scripts/forecasting_generalization.py \
--compact \
--no-hyperopt \
--output docs/assets/nyc_taxi_benchmarks/forecasting_generalization_scalable_synthetic.json

PYTEST_DISABLE_PLUGIN_AUTOLOAD=1 uv run --no-sync --group dev --group bench python scripts/forecasting_library_benchmark.py \
--suite synthetic \
--source polars \
--days 120 \
--lanes 4 \
--horizon 7 \
--suite-folds 2 \
--model-roster piecewise \
--no-candidate-selection \
--no-hyperopt \
--cartoboost-n-estimators 5 \
--cartoboost-auto-n-estimators 5 \
--output target/forecasting_piecewise_local_suite.json \
--plot-dir docs/assets/nyc_taxi_benchmarks/piecewise_local_plots

uv run --group dev python scripts/forecasting_m4.py \
--committed \
--no-hyperopt \
--output docs/assets/nyc_taxi_benchmarks/forecasting_overhaul_m4_committed.json

uv run --group dev --group bench python scripts/forecasting_m5.py \
--committed \
--official-wrmsse \
--no-hyperopt \
--output docs/assets/nyc_taxi_benchmarks/forecasting_overhaul_m5_committed.json

uv run --group dev --group bench python scripts/forecasting_m6.py \
--committed \
--official-style \
--no-hyperopt \
--output docs/assets/nyc_taxi_benchmarks/forecasting_overhaul_m6_committed.json

Larger comparison runs:

uv run --group dev --group bench python scripts/forecasting_library_benchmark.py \
--source m5 \
--model-roster full \
--m5-data-dir data/forecasting_benchmarks/m5 \
--m5-series-limit 100 \
--m5-history-days 90 \
--no-hyperopt \
--output docs/assets/nyc_taxi_benchmarks/forecasting_m5_full_roster_sample.json \
--plot-dir docs/assets/nyc_taxi_benchmarks/forecasting_m5_full_roster_plots

uv run --group dev --group bench python scripts/forecasting_library_benchmark.py \
--source m6 \
--model-roster full \
--m6-assets-path data/forecasting_benchmarks/m6/assets_m6.csv \
--m6-series-limit 0 \
--m6-horizon 28 \
--no-hyperopt \
--output docs/assets/nyc_taxi_benchmarks/forecasting_m6_full.json \
--plot-dir docs/assets/nyc_taxi_benchmarks/forecasting_m6_full_plots

Limits​

  • Real taxi demand covers January–April 2024, 24 lanes, and three 7-day rolling-origin folds.
  • Synthetic demand checks are diagnostics.
  • The CartoBoost piecewise local diagnostics are synthetic and should be read as wiring and behavior evidence for Prophet-shaped tasks, not broad real-data evidence.
  • M4 is a 96-series-per-group sample.
  • M5 full-roster evidence is a 100-series sample; the full-corpus artifact is a lag-only coverage run.
  • M6 is a daily-return proxy, not an official leaderboard submission.
  • Optional external baselines require their benchmark extras.