pymc_forecast.model#
Model-building core: the train/forecast Horizon and the primitives
that register time-series latents and observation variables against it.
The package’s central invariant (inherited from pyro / numpyro_forecast): one
model definition both trains and forecasts. In-sample time latents live on
variables dimmed "time"; the forecast horizon lives on separate
{name}_future variables dimmed "time_future". Those future variables
are absent from the fitted posterior, so pm.sample_posterior_predictive
replays the posterior in-sample and draws the future from the prior —
conditioned on the replayed parents (see tests/test_replay_mechanism.py).
A model is a callable (Horizon, covariates) -> None executed inside a
managed pm.Model whose coords carry real time coordinates. The horizon is
derived from the coords: future = len(covariates.time) - len(data.time).
- pymc_forecast.model.FORECAST_VAR = 'forecast'#
Reserved name of the forecast-horizon variable registered by
predict().
- pymc_forecast.model.MU_FORECAST_VAR = 'mu_future'#
Reserved name of the forecast-horizon noise-free latent predictor registered by
predict()(seeMU_VAR).
- pymc_forecast.model.MU_VAR = 'mu'#
Reserved name of the in-sample noise-free latent predictor registered by
predict()— the latent passed to it, before observation noise (for GLM-style models this is the linear predictor, not the distribution mean).
- pymc_forecast.model.OBS_VAR = 'obs'#
Reserved name of the observed (in-sample) variable registered by
predict().
- class pymc_forecast.model.ForecastingModel(priors=None)[source]#
Bases:
PriorConfig,ABCObject-oriented facade over the functional primitives.
Subclasses implement
model()and use the bound helperstime_series()/predict(), which thread the currentHorizonautomatically. An instance is a valid model function forbuild_model()and the forecaster classes.Priors are user-injectable (see
PriorConfig): a subclass declares its overridable defaults indefault_priorsand readsself.prior_config[...]in the model body; callers override any subset at construction time:from pymc_extras.prior import Prior class LocalLevel(ForecastingModel): default_priors = { "drift": Prior("Normal", mu=0, sigma=0.1), "noise": Prior("Normal", sigma=Prior("HalfNormal", sigma=1)), } def model(self, h, covariates): drift = self.time_series("drift", self.prior_config["drift"]) self.predict(self.prior_config["noise"], pt.cumsum(drift)) LocalLevel(priors={"drift": Prior("StudentT", nu=4, mu=0, sigma=0.2)})
- abstractmethod model(h, covariates)[source]#
Define the generative model; call
predict()exactly once.
- time_series(name, rv_fn, *, dims=())[source]#
Bound
time_series()using the current build’s horizon.
- class pymc_forecast.model.Horizon(data, time, time_future=<factory>)[source]#
Bases:
objectThe train/forecast split of a single model build, derived from coords.
- data#
Observed data (time-first
DataArray), orNonefor prior-only builds.- Type:
xarray.core.dataarray.DataArray | None
- time#
Coordinate values of the observed window (length
t_obs).- Type:
- time_future#
Coordinate values of the forecast horizon (empty while training).
- Type:
- property t_obs#
Number of observed (in-sample) time steps.
- property future#
Number of forecast time steps (
0while training).
- property duration#
Total horizon length
t_obs + future.
- pymc_forecast.model.build_model(model_fn, data, covariates, *, coords=None)[source]#
Build a
pm.Modelfrom a model function and (data, covariates).The horizon is derived from the time coords: covariates span the full horizon, data covers the observed prefix. Registered coords:
"time"(observed steps),"time_future"(forecast steps, only when forecasting), every non-time dim of data/covariates, plus any usercoords.- Parameters:
model_fn – The model body
(Horizon, covariates) -> Noneor aForecastingModelinstance.data – Observed data (DataArray / Series / DataFrame / ndarray), or
Nonefor a prior-only build over the whole covariate span.covariates – Covariates spanning the full horizon (use
null_covariates()if the model has none).coords – Extra coords to register on the model.
- pymc_forecast.model.predict(h, obs_fn, latent, *, dims=None)[source]#
Register the observation and forecast variables of the model.
latentis the deterministic full-horizon predictor (time on axis 0). The observed prefix becomes the likelihood ("obs", dims("time", *dims)); when forecasting, the suffix becomes the unobserved"forecast"variable (dims("time_future", *dims)) thatpm.sample_posterior_predictivedraws.The latent itself is also recorded, noise-free, as
"mu"(in-sample) and"mu_future"(forecast horizon) Deterministics — the documented way to separate parameter/latent uncertainty from observation noise (seedocs/schema.md). For GLM-style models this is the linear predictor passed topredict, not the distribution mean. The names"mu"and"mu_future"are therefore reserved: a model body must not define variables with these names.This single primitive covers both upstream
predict(location-family noise: passlambda name, mu, dims, observed: pm.Normal(name, mu, sigma, dims=dims, observed=observed)) and upstreampredict_glm(any link, e.g.lambda name, eta, dims, observed: pm.Poisson(name, pt.exp(eta), dims=dims, observed=observed)) — PyMC likelihoods take their parameters directly, so no distribution surgery is needed.- Parameters:
h – The horizon of the current model build.
obs_fn – Observation factory
(name, latent, dims, observed) -> RV. Must create the variable with exactly the dims it is given, and passobservedthrough. A pymc-extrasPrioris also accepted (e.g.Prior("Normal", sigma=Prior("HalfNormal", sigma=1))): its distribution becomes the likelihood with the latent as location, and nested hyper-priors are created once under"obs"and shared by the observed and forecast segments (seepymc_forecast.priors).latent – Full-horizon predictor with time on axis 0.
dims – Extra (non-time) dims of the observation. Default: inferred from the data’s non-time dims (
()for prior-only builds).
- pymc_forecast.model.time_series(h, name, rv_fn, *, dims=())[source]#
Sample a per-step latent over the full horizon.
Calls
rv_fn(name, ("time", *dims))for the observed window and — when forecasting —rv_fn(f"{name}_future", ("time_future", *dims))for the horizon, concatenating along time (axis 0). The future variable is what keeps the posterior blind to the horizon (see module docstring).- Parameters:
h – The horizon of the current model build.
name – Base variable name for the in-sample latent.
rv_fn – Factory creating the variable, e.g.
lambda name, dims: pm.Normal(name, 0, drift_scale, dims=dims). It must create the variable with exactly the dims it is given. A pymc-extrasPrioris also accepted (e.g.Prior("Normal", mu=0, sigma=0.1)); nested hyper-priors are created once undernameand shared by the in-sample and future segments (seepymc_forecast.priors).dims – Extra (non-time) dims of the latent, e.g.
("series",).
- Returns:
TensorVariable– The latent over the full horizon, time on axis 0.