MarkovSwitchingVAR.fit#

MarkovSwitchingVAR.fit(*, max_iter=500, tol=1e-6, n_init=10, screen_iter=15, seed=None)[source]#

Estimate by EM with multi-start screening.

Unlike the other multivariate families, fit takes arguments, because the likelihood is multimodal and the answer genuinely depends on where the search starts. The default screens n_init starts for screen_iter iterations each and refines only the best; pass a seed when the fit must be reproducible.

Parameters:
  • max_iter (int) – Iteration cap for the refining run.

  • tol (float) – Convergence tolerance on the log-likelihood increment.

  • n_init (int) – Starts to screen, the first being the linear fit split along whichever block switches.

  • screen_iter (int) – Iterations used to score each screening start.

  • seed (int | Generator | None) – Seed or generator for the random starts.

Return type:

MarkovSwitchingVARResult

Returns:

The fitted MarkovSwitchingVARResult, regimes ordered by the convention MarkovSwitchingVARResult.label_ordering names.

Raises:

NumericalError – If every start fails to produce a finite likelihood.

Example

The same seed gives the same fit. Screening matters even on a cleanly separated problem: the deterministic first start alone converges to a local optimum in which one persistent regime absorbs the mean shift, more than a hundred log-points below the screened fit:

>>> import numpy as np
>>> rng = np.random.default_rng(0)
>>> s = np.repeat([0, 1, 0, 1], 100)
>>> y = np.array([[-1.0, -0.5], [1.5, 1.0]])[s] + 0.4 * rng.standard_normal((400, 2))
>>> model = MarkovSwitchingVAR(y, order=1, n_regimes=2)
>>> one, two = model.fit(seed=0), model.fit(seed=0)
>>> one.llf == two.llf, one.converged, one.regime_shares.round(2)
(True, True, array([0.5, 0.5]))
>>> single = model.fit(seed=0, n_init=1)
>>> single.converged, bool(single.llf < one.llf - 100), single.regime_shares.round(2)
(True, True, array([0.92, 0.08]))