UnobservedComponents#

class cultivars.univariate.unobserved_components.UnobservedComponents(endog, *, trend='level', cycle=False, seasonal=None)[source]

Bases: _UnobservedComponentsModel[UnobservedComponentsResult]

Structural time-series decomposition by exact maximum likelihood.

Harvey’s basic structural model: a trend, optionally a damped stochastic cycle and a trigonometric seasonal, each with its own innovation variance, observed through an irregular. The specification is fixed at construction; fit maximizes the exact Gaussian likelihood over the log variances (and, for the cycle, the damping and frequency through sigmoid maps, so the search is unconstrained) by L-BFGS-B from data-scaled starts – two of them when a cycle is present – then runs the fixed-interval smoother so every component is reported with its band.

The three trends answer different questions. "level" is the local level \(\mu_{t+1} = \mu_t + \eta_t\), an exponentially weighted moving average with its smoothing weight estimated. "lltrend" adds a random-walk slope, so both the level and its growth rate drift. "smooth" keeps the slope but removes the level innovation, an integrated random walk whose smoothed level is a maximum-likelihood cubic smoothing spline – the model-based counterpart of the Hodrick-Prescott filter with its smoothing constant estimated rather than imposed.

Variables:
  • _endog – The observed series as a float array, shape (n,).

  • _trend – The trend specification.

  • _cycle – Whether the damped stochastic cycle is present.

  • _seasonal – The trigonometric seasonal period, or None.

Parameters:
  • endog (ArrayLike) – The observed series.

  • trend (str) – "level" for a local level, "lltrend" for a local linear trend, "smooth" for an integrated random walk.

  • cycle (bool) – Whether to estimate a damped stochastic cycle (damping, frequency and variance all estimated).

  • seasonal (int | None) – Trigonometric seasonal period, at least 2, or None.

Raises:
  • SpecificationError – If trend is not one of the three names or seasonal is below 2.

  • DimensionError – If the series is shorter than 3 m + 10 for the specification’s m states, or is not one-dimensional.

See also

  • UnobservedComponentsResult – the record fit returns.

  • UCSV – the local level with time-varying variances, estimated by Gibbs sampling.

  • AR – the reduced-form alternative to a structural decomposition.

References

Harvey, A. C. (1989). Forecasting, Structural Time Series Models and the Kalman Filter. Cambridge University Press, ch. 2.

Harvey, A. C., & Jaeger, A. (1993). Detrending, stylized facts and the business cycle. Journal of Applied Econometrics, 8(3), 231-247.

Example

A local level recovers the random walk under the noise, and the three trends are ranked on BIC for a series whose slope drifts:

>>> import numpy as np
>>> rng = np.random.default_rng(0)
>>> n = 300
>>> level = np.cumsum(0.1 * rng.standard_normal(n))
>>> y = level + 0.5 * rng.standard_normal(n)
>>> res = UnobservedComponents(y, trend="level").fit()
>>> bool(np.mean((res.level - level) ** 2) < np.mean((y - level) ** 2))
True
>>> rng = np.random.default_rng(7)
>>> slope = np.cumsum(0.01 * rng.standard_normal(n))
>>> y = np.cumsum(slope) + 0.5 * rng.standard_normal(n)
>>> trends = ("level", "lltrend", "smooth")
>>> fits = {t: UnobservedComponents(y, trend=t).fit() for t in trends}
>>> bic = {t: fit.information_criteria.bic for t, fit in fits.items()}
>>> bool(bic["smooth"] < bic["lltrend"] < bic["level"])
True
>>> UnobservedComponents(y, trend="quadratic")
Traceback (most recent call last):
cultivars.exceptions.SpecificationError: trend must be 'level', 'lltrend', or 'smooth'; ...