prophet-laplace
"He's not the messiah. He's a very naughty boy." (why) This package makes him useful anyway.
Prophet in a laplace sandwich: the same Prophet API, with calibrated
predictive densities. SandwichedProphet fits
Prophet in the
z-coordinates of a skaters
laplace forecaster and maps every forecast back through the
exact inverse. Prophet keeps its calendar decomposition, holidays, and
extra regressors; the sandwich adds the volatility clock, repeated-value
handling, and tails whose stated probabilities come true.
Quickstart
The API mirrors Prophet. Fit on a frame with ds and
y, then predict on a future frame.
import pandas as pd
from prophet_laplace import SandwichedProphet
m = SandwichedProphet(k=30) # k = forecast horizon, in observations
m.fit(df) # df has columns ds, y (+ any regressors)
future = pd.DataFrame({"ds": pd.date_range(df["ds"].max() + pd.Timedelta(days=1),
periods=30, freq="D")})
fc = m.predict(future) # yhat / yhat_lower / yhat_upper, mapped back exactly
The point and interval columns are the median and central 68.27% band of the sandwiched predictive, so the interval reflects the volatility clock and tails rather than Prophet's Gaussian assumption. Extra regressors and Prophet keyword arguments pass straight through.
Calibrated densities
The reason to sandwich is the full predictive density, not just the
interval. predictive returns a y-space distribution with
logpdf, cdf, and quantile, with
exact change-of-variables accounting.
pred = m.predictive(step=1, z_mu=0.0, z_sigma=1.0)
pred.quantile(0.99) # upper 1% level, tail-aware
pred.logpdf(y_obs) # score a realised observation
pred.cdf(y_obs) # PIT value; uniform under calibration
How it works
laplace defines a causal bijection on paths, the Rosenblatt
transform zt = Φ−1(Ft(yt)),
where Ft is the predictive cdf laplace
issued for yt. Under calibration the z stream is close
to i.i.d. standard normal, so Prophet is handed a stationarised,
unit-scale series and its calendar model works on structure that survives
the transform.
Every density maps back with no approximation in the accounting:
log fY(y) = log fZ(z) +
log ft(y) − log φ(z). Running an
opponent between the transform and its inverse is the sandwich;
whatever the inner model finds is, by construction, structure
laplace alone did not capture.
The measured gap
Measured on 921 non-price FRED series under a pre-registered protocol (statements filed before results, frozen universe, harness and results committed in the skaters repository):
| median one-step LL vs laplace | family-weighted (120 families) | |
|---|---|---|
| Prophet raw | −0.755 nats | −4.60 nats |
| Prophet sandwiched | −0.020 nats | −0.025 nats |
The sandwich closes 97% of Prophet's density gap without retraining anything. The residual 0.02 nats is the epsilon: conditional structure neither model captures. The same construction lifts other forecasters and detectors, tabled on the sandwich page.