PerturbationDSGE.fit#

PerturbationDSGE.fit(theta0=None, *, filter='unscented', n_particles=500, seed=None)[source]#

Maximize one filter’s likelihood from a starting point.

Parameters:
  • theta0 (ArrayLike | None) – Starting structural parameters. Required: a DSGE likelihood has no data-driven warm start.

  • filter (str) – "kalman" (exact, first order only), "extended", "unscented", or "particle" (common random numbers, Nelder-Mead).

  • n_particles (int) – Particles under "particle".

  • seed (int | None) – The common seed under "particle".

Return type:

PerturbationDSGEResult

Returns:

The PerturbationDSGEResult at the optimum.

Raises:

SpecificationError – If theta0 is missing or the filter is incompatible with the order.

Example

>>> import numpy as np
>>> class Latent:
...     parameter_names, bounds = ("rho", "sigma"), ((0.0, 0.99), (0.01, 1.0))
...     n_states, n_controls = 1, 1
...     def equations(self, th, y_next, y, x_next, x):
...         return np.array([y[0] - x[0], x_next[0] - th[0] * x[0]])
...     def steady_state(self, th):
...         return np.zeros(1), np.zeros(1)
...     def shock_loading(self, th):
...         return np.array([[th[1]]])
...     def observation(self, th):
...         return np.array([[0.0, 1.0]]), np.zeros(1), np.array([[1e-4]])
...     def log_prior(self, th):
...         return 0.0
>>> rng = np.random.default_rng(0)
>>> x = np.zeros(200)
>>> for t in range(1, 200):
...     x[t] = 0.8 * x[t - 1] + 0.5 * rng.standard_normal()
>>> second = PerturbationDSGE(Latent(), x, order=2)
>>> res = second.fit([0.5, 0.3], filter="extended")
>>> res.filter, {name: round(value, 2) for name, value in res.params.items()}
('extended', {'rho': 0.82, 'sigma': 0.48})
>>> second.fit()
Traceback (most recent call last):
cultivars.exceptions.SpecificationError: theta0 is required: supply starting ...
>>> second.fit([0.5, 0.3], filter="kalman")
Traceback (most recent call last):
cultivars.exceptions.SpecificationError: filter='kalman' is exact only at order=1; ...