Skip to content

Linear growth benchmarks ​

53 of 55 cases match Python Prophet. 2 are intentional differences, explained below.

Each case runs the same input through Effect Prophet and Python Prophet 1.4.0, then compares every forecast row, the trend, each component and the fitted noise. A case matches when all of them agree within its tolerances, and only matching cases are timed.

Each case's dot shows its result: matches, matches with internal differences flagged, intentional difference, doesn't match. Hover over a dot for details.

How to read the tables:

  • Effect output and Python output are each library's final forecast value. Open a case to see every row side by side.
  • Largest difference is the biggest gap between the two forecasts, as a share of the input data's range.
  • Effect time and Python time are the median time for the timed step, usually fitting and predicting. Open a case for every step, including first-run and save/load times.
  • A timed step marked different work calls public operations that produce different outputs in the two libraries, so its times aren't a speed comparison. The case page explains the difference.
  • Flagged cases match, but the two libraries stopped their fitting search at slightly different points. The case page shows the internal numbers.
About this run
  • Run 2026-11-07T174133-142Z-3a5a6cec on 2026-11-07, commit 3a5a6ce
  • Both libraries ran in linux/arm64 containers on Apple M4 Pro
  • effect-prophet 0.0.0
  • effect 4.0.6
  • prophet 1.4.0
  • Full benchmark report

Timings come from one machine and describe this workload only. They are not a general speed ranking. Where Python is faster, it is often because Python runs Stan's optimizer as compiled C++, while Effect Prophet runs the same algorithm as WebAssembly with narrower vector instructions. The gap is widest for Newton's method on short histories with many parameters.

Country holiday calendars ​

Pinned country calendars, matching explicit-event controls, dynamic future years and portable saved models. Known-gap opt-in is partial provider output, not a completeness guarantee.

CaseInputEffect outputPython outputLargest differenceTimed stepEffect timePython time
US holidays, additive96 rows21.568821.5688< 0.0001%Fit and predict4.49 ms26.6 ms
Explicit US control, additive96 rows21.568821.5688< 0.0001%Fit and predict3.94 ms23.1 ms
US holidays, multiplicative96 rows21.577821.5778< 0.0001%Fit and predict4.76 ms27.4 ms
Explicit US control, multiplicative96 rows21.577821.5778< 0.0001%Fit and predict4.48 ms23.6 ms
Observed spillovers and unseen future names96 rows33.938533.9385< 0.0001%Fit and predict5.28 ms27.8 ms
Global prior scales96 rows20.867420.8674< 0.0001%Fit and predict5.09 ms33.8 ms
Global prior scales with explicit overrides96 rows20.872720.8727< 0.0001%Fit and predict5.11 ms33.9 ms

Default settings ​

fit(history) against Prophet().fit(df) with no options on either side. Each library decides on its own which seasonal patterns to use. Warm-start cases fit the first rows, then refit the whole history from the parameters of that fit, as when new data arrives.

CaseInputEffect outputPython outputLargest differenceTimed stepEffect timePython time
Defaults, one month of daily data32 rows30.793330.7933< 0.0001%Fit and predict18.4 ms64.1 ms
Refit after a month of new data256 rows139.9296139.92720.0025%Refit from an earlier fit27.3 ms73.2 ms
Refit after one new day256 rows139.9300139.92880.0012%Refit from an earlier fit8.14 ms21.5 ms
Defaults, eight months of daily data256 rows139.9296139.92780.0018%Fit and predict26.5 ms89.9 ms
Defaults, irregular dates192 rows108.5108108.43200.11%Fit and predict6.80 ms17.1 ms

Straight-line and bending trends with automatic or hand-picked changepoints, plus unsorted rows, repeated timestamps and both target scalings.

CaseInputEffect outputPython outputLargest differenceTimed stepEffect timePython time
Predicting from a known straight line256 rows43.780443.7804< 0.0001%Predict532 µs2.64 ms
One hand-picked changepoint32 rows28.515628.5156< 0.0001%Fit and predict2.11 ms13.8 ms
Sorted rows, hand-picked changepoint96 rows34.414534.4145< 0.0001%Fit4.34 ms20.8 ms
Sorted rows, automatic changepoints96 rows34.425834.4258< 0.0001%Fit30.9 ms108 ms
Shuffled rows, hand-picked changepoint96 rows34.414534.4145< 0.0001%Fit4.31 ms20.8 ms
Shuffled rows, automatic changepoints96 rows34.425834.4258< 0.0001%Fit32.0 ms109 ms
Repeated timestamps, hand-picked changepoint96 rows17.873717.8737< 0.0001%Fit4.05 ms19.8 ms
Repeated timestamps, automatic changepoints96 rows17.903917.90390.0013%Fit26.4 ms84.9 ms
Values far from zero, absmax scaling96 rows113.0935113.0935< 0.0001%Fit and predict4.91 ms26.7 ms
Values far from zero, minmax scaling96 rows113.0928113.0928< 0.0001%Fit and predict5.03 ms26.9 ms

Seasonality, events and regressors ​

Custom and switchable seasonal patterns, events with windows, extra regressors, and additive and multiplicative effects mixed together.

CaseInputEffect outputPython outputLargest differenceTimed stepEffect timePython time
Weekly pattern on irregular dates192 rows108.5119108.5118< 0.0001%Fit and predict1.99 ms11.1 ms
Two switchable weekly patterns256 rows139.4380139.43530.0028%Fit and predict2.77 ms16.8 ms
Events with windows96 rows54.282154.2821< 0.0001%Fit and predict6.75 ms34.0 ms
Four regressors256 rows138.7384138.74260.0043%Fit and predict2.65 ms14.1 ms
A regressor forecast by its own model256 rows139.2608139.26480.0040%Fit and predict28.6 ms119 ms
Everything at once, small24 rows21.202521.2025< 0.0001%Fit and predict1.79 ms16.0 ms
Everything at once, two years768 rows54.271654.26570.038%Fit and predict11.8 ms44.3 ms
Additive and multiplicative together96 rows44.518344.5183< 0.0001%Fit and predict4.92 ms29.5 ms
Repeated timestamps with features96 rows18.219118.22000.017%Fit31.9 ms113 ms

Uncertainty ranges ​

Both libraries simulate possible futures with random draws, so individual simulated values never match. Each range must still match Python's within the variation expected from that many draws. Anomaly cases also check that both libraries flag the outliers in a history.

CaseInputEffect outputPython outputLargest differenceTimed stepEffect timePython time
Ranges with a forecast regressor256 rows139.2608139.26480.0040%Simulate uncertainty (different work)9.28 ms246 ms
Defaults, three years of ranges1095 rows611.2687611.31560.011%Simulate uncertainty (different work)69.7 ms375 ms
Defaults, ranges on irregular dates192 rows108.5108108.43200.15%Simulate uncertainty (different work)11.4 ms158 ms
Samples with repeated timestamps96 rows17.903917.90390.0013%Simulate uncertainty (different work)471 µs16.8 ms
Ranges over past dates96 rows110.0950110.0950< 0.0001%Simulate uncertainty (different work)331 µs19.8 ms
Samples for one future date96 rows110.0819110.0819< 0.0001%Simulate uncertainty (different work)204 µs16.8 ms
Ranges with mixed effects96 rows45.135345.1353< 0.0001%Simulate uncertainty (different work)487 µs26.4 ms
Samples with mixed effects96 rows45.135345.1353< 0.0001%Simulate uncertainty (different work)798 µs68.6 ms
Anomalies in a history365 rows149.0161148.99470.11%Fit and find anomalies25.2 ms199 ms

Full Bayesian fitting ​

fit(history, { mcmc: { samples, seed } }) against Prophet(mcmc_samples=...) and fit(df, seed=...): both run Stan's NUTS sampler with the same settings. Their chains can't match draw for draw, so each forecast, component and coefficient, a posterior mean, must agree within 0.15 of the narrowest 80% range, and each range bound within the variation expected from that many posterior draws. Divergences and R-hat are reported, and flagged when Effect's chains mix clearly worse than Python's.

CaseInputEffect outputPython outputLargest differenceTimed stepEffect timePython time
Mixed features, 600 draws96 rows44.513944.51940.019%Simulate uncertainty (different work)2.95 ms164 ms
25 automatic changepoints256 rows139.9330139.93390.00091%Simulate uncertainty (different work)7.58 ms153 ms
A regressor forecast by its own model256 rows139.2825139.26470.019%Simulate uncertainty (different work)16.1 ms306 ms
A regressor forecast by its own sampled model256 rows139.2723139.25470.019%Simulate uncertainty (different work)16.3 ms500 ms

Cross-validation and choosing settings ​

Rolling-origin cross-validation, metrics, baselines, settings search and a final holdout check.

CaseInputEffect outputPython outputLargest differenceTimed stepEffect timePython time
Cross-validation with a forecast regressor256 rows106.8125106.81240.0025%Cross-validate (different work)51.6 ms185 ms
Cross-validation with a forecast regressor and ranges256 rows106.8125106.81240.0025%Cross-validate with ranges (different work)51.9 ms255 ms
Cross-validation and metrics96 rows108.5823108.5823< 0.0001%Cross-validate (different work)10.1 ms72.0 ms
Cross-validation with ranges96 rows108.5823108.5823< 0.0001%Cross-validate with ranges (different work)10.5 ms78.2 ms
Choosing settings and a final holdout96 rows108.5823108.5823< 0.0001%Search settings (different work)20.2 ms151 ms
Search with a failing candidate96 rows108.5823108.5823< 0.0001%Search settings (different work)21.4 ms153 ms
Choosing settings by a custom metric96 rows108.5823108.5823< 0.0001%Search settings (different work)20.4 ms143 ms
Twelve folds, three years, sequential and parallel1095 rows420.8894420.83230.052%Cross-validate (different work)953 ms2.61 s
Cross-validation with repeated timestamps96 rows15.522115.5221< 0.0001%Cross-validate (different work)6.85 ms53.4 ms

Intentional differences ​

Inputs where we deliberately behave differently from Python Prophet. These cases are expected to fail the comparison.

CaseInputEffect outputPython outputLargest differenceTimed stepEffect timePython time
Every row on the same date, different values3 rowsFittingErrorOptimizer crash————
Every row on the same date, same value3 rowsFittingErrorNaN forecast————

Inspired by Prophet from Meta. Not affiliated with Meta.