prophet-laplace 0.0.1__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- prophet_laplace-0.0.1/LICENSE +3 -0
- prophet_laplace-0.0.1/PKG-INFO +65 -0
- prophet_laplace-0.0.1/README.md +47 -0
- prophet_laplace-0.0.1/pyproject.toml +22 -0
- prophet_laplace-0.0.1/setup.cfg +4 -0
- prophet_laplace-0.0.1/src/prophet_laplace/__init__.py +18 -0
- prophet_laplace-0.0.1/src/prophet_laplace/sandwich.py +116 -0
- prophet_laplace-0.0.1/src/prophet_laplace.egg-info/PKG-INFO +65 -0
- prophet_laplace-0.0.1/src/prophet_laplace.egg-info/SOURCES.txt +11 -0
- prophet_laplace-0.0.1/src/prophet_laplace.egg-info/dependency_links.txt +1 -0
- prophet_laplace-0.0.1/src/prophet_laplace.egg-info/requires.txt +3 -0
- prophet_laplace-0.0.1/src/prophet_laplace.egg-info/top_level.txt +1 -0
- prophet_laplace-0.0.1/tests/test_sandwich.py +50 -0
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: prophet-laplace
|
|
3
|
+
Version: 0.0.1
|
|
4
|
+
Summary: Prophet in a laplace sandwich: same API, calibrated densities
|
|
5
|
+
Author: Peter Cotton
|
|
6
|
+
License: MIT
|
|
7
|
+
Project-URL: Homepage, https://github.com/microprediction/prophet-laplace
|
|
8
|
+
Project-URL: Repository, https://github.com/microprediction/prophet-laplace
|
|
9
|
+
Project-URL: Sandwich explainer, https://skaters.microprediction.org/sandwich.html
|
|
10
|
+
Keywords: prophet,forecasting,calibration,time-series,skaters,laplace
|
|
11
|
+
Requires-Python: >=3.9
|
|
12
|
+
Description-Content-Type: text/markdown
|
|
13
|
+
License-File: LICENSE
|
|
14
|
+
Requires-Dist: prophet>=1.1
|
|
15
|
+
Requires-Dist: skaters>=0.13.0
|
|
16
|
+
Requires-Dist: pandas
|
|
17
|
+
Dynamic: license-file
|
|
18
|
+
|
|
19
|
+
# prophet-laplace
|
|
20
|
+
|
|
21
|
+
*"He's not the messiah. He's a very naughty boy."* ([why](https://medium.com/geekculture/is-facebooks-prophet-the-time-series-messiah-or-just-a-very-naughty-boy-8b71b136bc8c)) *This package makes him useful anyway.*
|
|
22
|
+
|
|
23
|
+
Prophet in a laplace sandwich: same API, calibrated densities.
|
|
24
|
+
|
|
25
|
+
```python
|
|
26
|
+
from prophet_laplace import SandwichedProphet
|
|
27
|
+
|
|
28
|
+
m = SandwichedProphet(k=30) # accepts Prophet's kwargs too
|
|
29
|
+
m.fit(df) # ds, y (+ regressors as usual)
|
|
30
|
+
fc = m.predict(future) # yhat / yhat_lower / yhat_upper,
|
|
31
|
+
# mapped back exactly
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
## What it does
|
|
35
|
+
|
|
36
|
+
`SandwichedProphet` fits Prophet in the z-coordinates of a
|
|
37
|
+
[skaters](https://github.com/microprediction/skaters) laplace forecaster
|
|
38
|
+
(the Rosenblatt transform of each observation under the predictive issued
|
|
39
|
+
for it) and maps every forecast back through the exact inverse. Prophet
|
|
40
|
+
keeps its calendar decomposition, holidays, and extra regressors; the
|
|
41
|
+
sandwich supplies the volatility clock, repeated-value handling, and
|
|
42
|
+
tails whose stated probabilities come true.
|
|
43
|
+
|
|
44
|
+
## Why
|
|
45
|
+
|
|
46
|
+
Measured on 921 non-price FRED series under a pre-registered protocol
|
|
47
|
+
(statements, frozen universe, and results in the skaters repository):
|
|
48
|
+
|
|
49
|
+
| | median one-step LL vs laplace | family-weighted (120 families) |
|
|
50
|
+
|------------|------------------------------|-------------------------------|
|
|
51
|
+
| Prophet raw | -0.755 nats | -4.60 nats |
|
|
52
|
+
| Prophet sandwiched | **-0.020 nats** | **-0.025 nats** |
|
|
53
|
+
|
|
54
|
+
The sandwich closes 97% of Prophet's density gap without retraining
|
|
55
|
+
anything. `predictive(step, z_mu, z_sigma)` exposes the full y-space
|
|
56
|
+
density (logpdf, cdf, quantile) for scoring and risk use.
|
|
57
|
+
|
|
58
|
+
The same construction lifts other forecasters and detectors too:
|
|
59
|
+
[skaters.microprediction.org/sandwich.html](https://skaters.microprediction.org/sandwich.html).
|
|
60
|
+
|
|
61
|
+
## Status
|
|
62
|
+
|
|
63
|
+
v0: future frames only, horizons past `k` reuse the k-step transport
|
|
64
|
+
(disclosed approximation). The goal is to demonstrate interoperability,
|
|
65
|
+
then propose the option upstream.
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
# prophet-laplace
|
|
2
|
+
|
|
3
|
+
*"He's not the messiah. He's a very naughty boy."* ([why](https://medium.com/geekculture/is-facebooks-prophet-the-time-series-messiah-or-just-a-very-naughty-boy-8b71b136bc8c)) *This package makes him useful anyway.*
|
|
4
|
+
|
|
5
|
+
Prophet in a laplace sandwich: same API, calibrated densities.
|
|
6
|
+
|
|
7
|
+
```python
|
|
8
|
+
from prophet_laplace import SandwichedProphet
|
|
9
|
+
|
|
10
|
+
m = SandwichedProphet(k=30) # accepts Prophet's kwargs too
|
|
11
|
+
m.fit(df) # ds, y (+ regressors as usual)
|
|
12
|
+
fc = m.predict(future) # yhat / yhat_lower / yhat_upper,
|
|
13
|
+
# mapped back exactly
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
## What it does
|
|
17
|
+
|
|
18
|
+
`SandwichedProphet` fits Prophet in the z-coordinates of a
|
|
19
|
+
[skaters](https://github.com/microprediction/skaters) laplace forecaster
|
|
20
|
+
(the Rosenblatt transform of each observation under the predictive issued
|
|
21
|
+
for it) and maps every forecast back through the exact inverse. Prophet
|
|
22
|
+
keeps its calendar decomposition, holidays, and extra regressors; the
|
|
23
|
+
sandwich supplies the volatility clock, repeated-value handling, and
|
|
24
|
+
tails whose stated probabilities come true.
|
|
25
|
+
|
|
26
|
+
## Why
|
|
27
|
+
|
|
28
|
+
Measured on 921 non-price FRED series under a pre-registered protocol
|
|
29
|
+
(statements, frozen universe, and results in the skaters repository):
|
|
30
|
+
|
|
31
|
+
| | median one-step LL vs laplace | family-weighted (120 families) |
|
|
32
|
+
|------------|------------------------------|-------------------------------|
|
|
33
|
+
| Prophet raw | -0.755 nats | -4.60 nats |
|
|
34
|
+
| Prophet sandwiched | **-0.020 nats** | **-0.025 nats** |
|
|
35
|
+
|
|
36
|
+
The sandwich closes 97% of Prophet's density gap without retraining
|
|
37
|
+
anything. `predictive(step, z_mu, z_sigma)` exposes the full y-space
|
|
38
|
+
density (logpdf, cdf, quantile) for scoring and risk use.
|
|
39
|
+
|
|
40
|
+
The same construction lifts other forecasters and detectors too:
|
|
41
|
+
[skaters.microprediction.org/sandwich.html](https://skaters.microprediction.org/sandwich.html).
|
|
42
|
+
|
|
43
|
+
## Status
|
|
44
|
+
|
|
45
|
+
v0: future frames only, horizons past `k` reuse the k-step transport
|
|
46
|
+
(disclosed approximation). The goal is to demonstrate interoperability,
|
|
47
|
+
then propose the option upstream.
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
[project]
|
|
2
|
+
name = "prophet-laplace"
|
|
3
|
+
version = "0.0.1"
|
|
4
|
+
description = "Prophet in a laplace sandwich: same API, calibrated densities"
|
|
5
|
+
readme = "README.md"
|
|
6
|
+
license = {text = "MIT"}
|
|
7
|
+
requires-python = ">=3.9"
|
|
8
|
+
authors = [{name = "Peter Cotton"}]
|
|
9
|
+
keywords = ["prophet", "forecasting", "calibration", "time-series", "skaters", "laplace"]
|
|
10
|
+
dependencies = ["prophet>=1.1", "skaters>=0.13.0", "pandas"]
|
|
11
|
+
|
|
12
|
+
[project.urls]
|
|
13
|
+
Homepage = "https://github.com/microprediction/prophet-laplace"
|
|
14
|
+
Repository = "https://github.com/microprediction/prophet-laplace"
|
|
15
|
+
"Sandwich explainer" = "https://skaters.microprediction.org/sandwich.html"
|
|
16
|
+
|
|
17
|
+
[build-system]
|
|
18
|
+
requires = ["setuptools>=68"]
|
|
19
|
+
build-backend = "setuptools.build_meta"
|
|
20
|
+
|
|
21
|
+
[tool.setuptools.packages.find]
|
|
22
|
+
where = ["src"]
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
"""prophet-laplace: Prophet in a laplace sandwich.
|
|
2
|
+
|
|
3
|
+
Same Prophet API, calibrated densities. A SandwichedProphet fits Prophet
|
|
4
|
+
in the z-coordinates of a laplace forecaster (the Rosenblatt transform of
|
|
5
|
+
each observation under the predictive issued for it) and maps every
|
|
6
|
+
forecast back through the exact inverse. Prophet keeps its calendar
|
|
7
|
+
machinery, holidays, and extra regressors; the sandwich supplies the
|
|
8
|
+
volatility clock, the lattice handling, and tails that keep their stated
|
|
9
|
+
rates.
|
|
10
|
+
|
|
11
|
+
Measured on 921 non-price FRED series (pre-registered, see the skaters
|
|
12
|
+
repository): raw Prophet trails laplace by 0.76 nats median one-step
|
|
13
|
+
log-likelihood (family-weighted 4.6); sandwiched, the gap is 0.02.
|
|
14
|
+
"""
|
|
15
|
+
from prophet_laplace.sandwich import SandwichedProphet
|
|
16
|
+
|
|
17
|
+
__all__ = ["SandwichedProphet"]
|
|
18
|
+
__version__ = "0.0.1"
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
"""The sandwich: laplace transform in front, Prophet inside, exact inverse behind."""
|
|
2
|
+
from __future__ import annotations
|
|
3
|
+
|
|
4
|
+
import math
|
|
5
|
+
|
|
6
|
+
import pandas as pd
|
|
7
|
+
|
|
8
|
+
from skaters import laplace
|
|
9
|
+
from skaters.tails import _phi_inv
|
|
10
|
+
|
|
11
|
+
_EPS = 1e-12
|
|
12
|
+
_SQRT2 = math.sqrt(2.0)
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
def _phi(z: float) -> float:
|
|
16
|
+
return 0.5 * math.erfc(-z / _SQRT2)
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
class _Predictive:
|
|
20
|
+
"""A y-space predictive assembled from Prophet's z-space Gaussian and
|
|
21
|
+
laplace's h-step transport, with exact change-of-variables accounting."""
|
|
22
|
+
|
|
23
|
+
def __init__(self, transport, z_mu: float, z_sigma: float):
|
|
24
|
+
self._t = transport
|
|
25
|
+
self._mu = z_mu
|
|
26
|
+
self._sd = max(z_sigma, 1e-9)
|
|
27
|
+
|
|
28
|
+
def quantile(self, p: float) -> float:
|
|
29
|
+
z = self._mu + self._sd * _phi_inv(min(max(p, _EPS), 1.0 - _EPS))
|
|
30
|
+
u = min(max(_phi(z), _EPS), 1.0 - _EPS)
|
|
31
|
+
return self._t.quantile(u)
|
|
32
|
+
|
|
33
|
+
def logpdf(self, y: float) -> float:
|
|
34
|
+
u = min(max(self._t.cdf(y), _EPS), 1.0 - _EPS)
|
|
35
|
+
z = _phi_inv(u)
|
|
36
|
+
r = (z - self._mu) / self._sd
|
|
37
|
+
log_fz = -0.5 * r * r - math.log(self._sd) - 0.5 * math.log(2 * math.pi)
|
|
38
|
+
log_phi = -0.5 * z * z - 0.5 * math.log(2 * math.pi)
|
|
39
|
+
return log_fz + self._t.logpdf(y) - log_phi
|
|
40
|
+
|
|
41
|
+
def cdf(self, y: float) -> float:
|
|
42
|
+
u = min(max(self._t.cdf(y), _EPS), 1.0 - _EPS)
|
|
43
|
+
z = _phi_inv(u)
|
|
44
|
+
return _phi((z - self._mu) / self._sd)
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
class SandwichedProphet:
|
|
48
|
+
"""Drop-in Prophet with laplace-sandwiched coordinates.
|
|
49
|
+
|
|
50
|
+
Prophet keeps its API, calendar machinery, holidays, and extra
|
|
51
|
+
regressors; it just operates in the z-coordinates of a laplace
|
|
52
|
+
forecaster (the Rosenblatt transform of each observation under the
|
|
53
|
+
predictive issued for it), and every forecast maps back through the
|
|
54
|
+
exact inverse.
|
|
55
|
+
|
|
56
|
+
``k`` is the forecast horizon in observations; ``predict`` supports
|
|
57
|
+
future frames up to k steps past the training data (rows beyond k
|
|
58
|
+
reuse the k-step transport, a disclosed approximation).
|
|
59
|
+
"""
|
|
60
|
+
|
|
61
|
+
def __init__(self, k: int = 1, **prophet_kwargs):
|
|
62
|
+
from prophet import Prophet
|
|
63
|
+
self.k = int(k)
|
|
64
|
+
prophet_kwargs.setdefault("interval_width", 0.6827)
|
|
65
|
+
self._m = Prophet(**prophet_kwargs)
|
|
66
|
+
self._interval_z = 1.0 # 0.6827 central interval = +-1 sd
|
|
67
|
+
self._fitted = False
|
|
68
|
+
self._pending = None # k-step transport past training end
|
|
69
|
+
|
|
70
|
+
def add_regressor(self, name: str, **kw) -> "SandwichedProphet":
|
|
71
|
+
self._m.add_regressor(name, **kw)
|
|
72
|
+
return self
|
|
73
|
+
|
|
74
|
+
def fit(self, df: pd.DataFrame, **fit_kwargs) -> "SandwichedProphet":
|
|
75
|
+
f = laplace(self.k)
|
|
76
|
+
state = None
|
|
77
|
+
pend = None # dists issued for the arriving y
|
|
78
|
+
zs = []
|
|
79
|
+
for y in df["y"].astype(float).tolist():
|
|
80
|
+
if pend is None:
|
|
81
|
+
zs.append(0.0)
|
|
82
|
+
else:
|
|
83
|
+
u = min(max(pend[0].cdf(y), _EPS), 1.0 - _EPS)
|
|
84
|
+
zs.append(_phi_inv(u))
|
|
85
|
+
pend, state = f(y, state)
|
|
86
|
+
self._pending = pend # transport for steps 1..k ahead
|
|
87
|
+
zdf = df.copy()
|
|
88
|
+
zdf["y"] = zs
|
|
89
|
+
self._m.fit(zdf, **fit_kwargs)
|
|
90
|
+
self._last_ds = pd.to_datetime(df["ds"]).max()
|
|
91
|
+
self._fitted = True
|
|
92
|
+
return self
|
|
93
|
+
|
|
94
|
+
def _transport(self, step: int):
|
|
95
|
+
return self._pending[min(step, self.k) - 1]
|
|
96
|
+
|
|
97
|
+
def predictive(self, step: int, z_mu: float, z_sigma: float) -> _Predictive:
|
|
98
|
+
return _Predictive(self._transport(step), z_mu, z_sigma)
|
|
99
|
+
|
|
100
|
+
def predict(self, future: pd.DataFrame) -> pd.DataFrame:
|
|
101
|
+
assert self._fitted, "call fit first"
|
|
102
|
+
ds = pd.to_datetime(future["ds"])
|
|
103
|
+
assert (ds > self._last_ds).all(), (
|
|
104
|
+
"sandwich v0 maps future rows only; pass a frame strictly "
|
|
105
|
+
"after the training data")
|
|
106
|
+
fc = self._m.predict(future)
|
|
107
|
+
sds = ((fc["yhat_upper"] - fc["yhat_lower"]) / 2.0
|
|
108
|
+
/ self._interval_z).clip(lower=1e-9)
|
|
109
|
+
out = fc.copy()
|
|
110
|
+
for i in range(len(fc)):
|
|
111
|
+
pred = self.predictive(i + 1, float(fc["yhat"].iloc[i]),
|
|
112
|
+
float(sds.iloc[i]))
|
|
113
|
+
out.loc[out.index[i], "yhat"] = pred.quantile(0.5)
|
|
114
|
+
out.loc[out.index[i], "yhat_lower"] = pred.quantile(0.5 - 0.6827 / 2)
|
|
115
|
+
out.loc[out.index[i], "yhat_upper"] = pred.quantile(0.5 + 0.6827 / 2)
|
|
116
|
+
return out
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: prophet-laplace
|
|
3
|
+
Version: 0.0.1
|
|
4
|
+
Summary: Prophet in a laplace sandwich: same API, calibrated densities
|
|
5
|
+
Author: Peter Cotton
|
|
6
|
+
License: MIT
|
|
7
|
+
Project-URL: Homepage, https://github.com/microprediction/prophet-laplace
|
|
8
|
+
Project-URL: Repository, https://github.com/microprediction/prophet-laplace
|
|
9
|
+
Project-URL: Sandwich explainer, https://skaters.microprediction.org/sandwich.html
|
|
10
|
+
Keywords: prophet,forecasting,calibration,time-series,skaters,laplace
|
|
11
|
+
Requires-Python: >=3.9
|
|
12
|
+
Description-Content-Type: text/markdown
|
|
13
|
+
License-File: LICENSE
|
|
14
|
+
Requires-Dist: prophet>=1.1
|
|
15
|
+
Requires-Dist: skaters>=0.13.0
|
|
16
|
+
Requires-Dist: pandas
|
|
17
|
+
Dynamic: license-file
|
|
18
|
+
|
|
19
|
+
# prophet-laplace
|
|
20
|
+
|
|
21
|
+
*"He's not the messiah. He's a very naughty boy."* ([why](https://medium.com/geekculture/is-facebooks-prophet-the-time-series-messiah-or-just-a-very-naughty-boy-8b71b136bc8c)) *This package makes him useful anyway.*
|
|
22
|
+
|
|
23
|
+
Prophet in a laplace sandwich: same API, calibrated densities.
|
|
24
|
+
|
|
25
|
+
```python
|
|
26
|
+
from prophet_laplace import SandwichedProphet
|
|
27
|
+
|
|
28
|
+
m = SandwichedProphet(k=30) # accepts Prophet's kwargs too
|
|
29
|
+
m.fit(df) # ds, y (+ regressors as usual)
|
|
30
|
+
fc = m.predict(future) # yhat / yhat_lower / yhat_upper,
|
|
31
|
+
# mapped back exactly
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
## What it does
|
|
35
|
+
|
|
36
|
+
`SandwichedProphet` fits Prophet in the z-coordinates of a
|
|
37
|
+
[skaters](https://github.com/microprediction/skaters) laplace forecaster
|
|
38
|
+
(the Rosenblatt transform of each observation under the predictive issued
|
|
39
|
+
for it) and maps every forecast back through the exact inverse. Prophet
|
|
40
|
+
keeps its calendar decomposition, holidays, and extra regressors; the
|
|
41
|
+
sandwich supplies the volatility clock, repeated-value handling, and
|
|
42
|
+
tails whose stated probabilities come true.
|
|
43
|
+
|
|
44
|
+
## Why
|
|
45
|
+
|
|
46
|
+
Measured on 921 non-price FRED series under a pre-registered protocol
|
|
47
|
+
(statements, frozen universe, and results in the skaters repository):
|
|
48
|
+
|
|
49
|
+
| | median one-step LL vs laplace | family-weighted (120 families) |
|
|
50
|
+
|------------|------------------------------|-------------------------------|
|
|
51
|
+
| Prophet raw | -0.755 nats | -4.60 nats |
|
|
52
|
+
| Prophet sandwiched | **-0.020 nats** | **-0.025 nats** |
|
|
53
|
+
|
|
54
|
+
The sandwich closes 97% of Prophet's density gap without retraining
|
|
55
|
+
anything. `predictive(step, z_mu, z_sigma)` exposes the full y-space
|
|
56
|
+
density (logpdf, cdf, quantile) for scoring and risk use.
|
|
57
|
+
|
|
58
|
+
The same construction lifts other forecasters and detectors too:
|
|
59
|
+
[skaters.microprediction.org/sandwich.html](https://skaters.microprediction.org/sandwich.html).
|
|
60
|
+
|
|
61
|
+
## Status
|
|
62
|
+
|
|
63
|
+
v0: future frames only, horizons past `k` reuse the k-step transport
|
|
64
|
+
(disclosed approximation). The goal is to demonstrate interoperability,
|
|
65
|
+
then propose the option upstream.
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
LICENSE
|
|
2
|
+
README.md
|
|
3
|
+
pyproject.toml
|
|
4
|
+
src/prophet_laplace/__init__.py
|
|
5
|
+
src/prophet_laplace/sandwich.py
|
|
6
|
+
src/prophet_laplace.egg-info/PKG-INFO
|
|
7
|
+
src/prophet_laplace.egg-info/SOURCES.txt
|
|
8
|
+
src/prophet_laplace.egg-info/dependency_links.txt
|
|
9
|
+
src/prophet_laplace.egg-info/requires.txt
|
|
10
|
+
src/prophet_laplace.egg-info/top_level.txt
|
|
11
|
+
tests/test_sandwich.py
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
prophet_laplace
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import math
|
|
2
|
+
import random
|
|
3
|
+
|
|
4
|
+
import pandas as pd
|
|
5
|
+
import pytest
|
|
6
|
+
|
|
7
|
+
from prophet_laplace import SandwichedProphet
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
def _df(n=400, seed=3):
|
|
11
|
+
rng = random.Random(seed)
|
|
12
|
+
ds = pd.date_range("2020-01-01", periods=n, freq="D")
|
|
13
|
+
lvl, ys = 0.0, []
|
|
14
|
+
for t in range(n):
|
|
15
|
+
vol = 2.0 if (t // 60) % 2 else 0.5
|
|
16
|
+
lvl += rng.gauss(0, vol)
|
|
17
|
+
ys.append(lvl + 3.0 * math.sin(2 * math.pi * t / 7))
|
|
18
|
+
return pd.DataFrame({"ds": ds, "y": ys})
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
def test_fit_predict_roundtrip():
|
|
22
|
+
df = _df()
|
|
23
|
+
m = SandwichedProphet(k=5).fit(df)
|
|
24
|
+
future = pd.DataFrame(
|
|
25
|
+
{"ds": pd.date_range(df["ds"].max() + pd.Timedelta(days=1),
|
|
26
|
+
periods=5, freq="D")})
|
|
27
|
+
fc = m.predict(future)
|
|
28
|
+
assert len(fc) == 5
|
|
29
|
+
assert (fc["yhat_lower"] <= fc["yhat"]).all()
|
|
30
|
+
assert (fc["yhat"] <= fc["yhat_upper"]).all()
|
|
31
|
+
assert fc["yhat"].abs().max() < 1e6
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
def test_predictive_density_is_wellformed():
|
|
35
|
+
df = _df()
|
|
36
|
+
m = SandwichedProphet(k=1).fit(df)
|
|
37
|
+
pred = m.predictive(1, 0.0, 1.0)
|
|
38
|
+
qs = [pred.quantile(p) for p in (0.01, 0.25, 0.5, 0.75, 0.99)]
|
|
39
|
+
assert all(b >= a for a, b in zip(qs, qs[1:]))
|
|
40
|
+
y0 = qs[2]
|
|
41
|
+
assert math.isfinite(pred.logpdf(y0))
|
|
42
|
+
assert 0.0 <= pred.cdf(y0) <= 1.0
|
|
43
|
+
assert abs(pred.cdf(qs[1]) - 0.25) < 0.05
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
def test_past_frames_rejected():
|
|
47
|
+
df = _df()
|
|
48
|
+
m = SandwichedProphet(k=1).fit(df)
|
|
49
|
+
with pytest.raises(AssertionError):
|
|
50
|
+
m.predict(df[["ds"]].tail(3))
|