---
url: https://jer-k.github.io/effect-prophet/benchmarks/bayesian.md
---

# Full Bayesian fitting benchmarks

**7 of 7 cases match Python Prophet.**

`mcmc` fits against Python's `mcmc_samples`, on every trend type. Both libraries run Stan's NUTS sampler with the same settings, so posterior means and ranges must agree within the variation expected from that many posterior draws.

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.

::: details About these runs

Each trend's cases come from that trend's own run.

**Linear growth**

* 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](https://github.com/jer-k/effect-prophet/blob/main/benchmark/results/retained/linear-growth/2026-11-07T174133-142Z-3a5a6cec/report.md)

**Flat growth**

* Run `2026-11-07T181422-912Z-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](https://github.com/jer-k/effect-prophet/blob/main/benchmark/results/retained/flat-growth/2026-11-07T181422-912Z-3a5a6cec/report.md)

**Logistic growth**

* Run `2026-11-07T184211-397Z-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](https://github.com/jer-k/effect-prophet/blob/main/benchmark/results/retained/logistic-growth/2026-11-07T184211-397Z-3a5a6cec/report.md)

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.

:::

## Linear growth

`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. [All linear growth benchmarks →](/benchmarks/linear)

| Case | Input | Effect output | Python output | Largest difference | Timed step | Effect time | Python time |
| --- | --- | ---: | ---: | ---: | --- | ---: | ---: |
| [Mixed features, 600 draws](/benchmarks/linear/mcmc-linear-mixed-components) | [96 rows](https://github.com/jer-k/effect-prophet/blob/main/benchmark/inputs/v1/linear-mixed-components.json) | 44.5139 | 44.5194 | 0.019% | Simulate uncertainty (different work) | 2.95 ms | 164 ms |
| [25 automatic changepoints](/benchmarks/linear/mcmc-linear-default-changepoints) | [256 rows](https://github.com/jer-k/effect-prophet/blob/main/benchmark/inputs/v1/linear-medium.json) | 139.9330 | 139.9339 | 0.00091% | Simulate uncertainty (different work) | 7.58 ms | 153 ms |
| [A regressor forecast by its own model](/benchmarks/linear/mcmc-linear-regressor-model) | [256 rows](https://github.com/jer-k/effect-prophet/blob/main/benchmark/inputs/v1/map-regressors-medium.json) | 139.2825 | 139.2647 | 0.019% | Simulate uncertainty (different work) | 16.1 ms | 306 ms |
| [A regressor forecast by its own sampled model](/benchmarks/linear/mcmc-linear-sampled-regressor-model) | [256 rows](https://github.com/jer-k/effect-prophet/blob/main/benchmark/inputs/v1/map-regressors-medium.json) | 139.2723 | 139.2547 | 0.019% | Simulate uncertainty (different work) | 16.3 ms | 500 ms |

## Flat growth

`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. [All flat growth benchmarks →](/benchmarks/flat)

| Case | Input | Effect output | Python output | Largest difference | Timed step | Effect time | Python time |
| --- | --- | ---: | ---: | ---: | --- | ---: | ---: |
| [Mixed features, two chains](/benchmarks/flat/mcmc-flat-mixed-components) | [96 rows](https://github.com/jer-k/effect-prophet/blob/main/benchmark/inputs/v1/flat-mixed-components.json) | 35.0285 | 35.0305 | 0.022% | Simulate uncertainty (different work) | 2.02 ms | 130 ms |

## Logistic growth

`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. [All logistic growth benchmarks →](/benchmarks/logistic)

| Case | Input | Effect output | Python output | Largest difference | Timed step | Effect time | Python time |
| --- | --- | ---: | ---: | ---: | --- | ---: | ---: |
| [Capacity, floor and a multiplicative regressor](/benchmarks/logistic/mcmc-logistic-explicit-floor-minmax) | [96 rows](https://github.com/jer-k/effect-prophet/blob/main/benchmark/inputs/v1/logistic-explicit-floor.json) | 72.2189 | 72.2188 | 0.0091% | Simulate uncertainty (different work) | 2.91 ms | 210 ms |
| [A year of changing growth rates](/benchmarks/logistic/mcmc-logistic-rate-changes) | [365 rows](https://github.com/jer-k/effect-prophet/blob/main/benchmark/inputs/v3/logistic-rate-changes.json) | 193.9262 | 193.9405 | 0.027% | Simulate uncertainty (different work) | 38.4 ms | 356 ms |
