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.