cultivars.univariate.regime_switching#

Markov-switching autoregression: the latent-regime counterpart to SETAR.

A \(K\)-regime autoregression whose intercept, autoregressive coefficients, and innovation variance may each switch with a latent first-order Markov chain \(S_t \in \{0, \ldots, K-1\}\),

\[y_t = c_{S_t} + \sum_{i=1}^{p} \phi_{i,S_t}\, y_{t-i} + \varepsilon_t, \qquad \varepsilon_t \sim N(0, \sigma^2_{S_t}), \qquad P_{ij} = \Pr(S_t = j \mid S_{t-1} = i).\]

Where cultivars.univariate.threshold computes the regime from something observable, here the regime is never observed at all: what comes back is a posterior over states at every date, and every reported quantity – fitted values, residuals, even the regime a date “is in” – is an expectation under that posterior rather than a fact about the data. The Hamilton filter produces the predicted and filtered posteriors and the likelihood,

\[ \begin{align}\begin{aligned}\Pr(S_t = j \mid y_{1:t-1}) = \sum_i P_{ij}\,\Pr(S_{t-1} = i \mid y_{1:t-1}), \qquad \Pr(S_t = j \mid y_{1:t}) \propto \Pr(S_t = j \mid y_{1:t-1})\, f(y_t \mid S_t = j, y_{1:t-1}),\\\log L = \sum_t \log \sum_j \Pr(S_t = j \mid y_{1:t-1})\, f(y_t \mid S_t = j, y_{1:t-1}),\end{aligned}\end{align} \]

and Kim’s backward pass turns them into the smoothed posterior \(\Pr(S_t = j \mid y_{1:T})\). Estimation is EM (Hamilton 1990): the E-step is that filter and smoother, the M-step updates the transition matrix from expected transition counts and the coefficients by responsibility-weighted least squares. The likelihood is multimodal, so MarkovSwitchingAR.fit() screens several random starts and refines the best – which is why fit takes a seed and why the result reports whether it converged.

Two commitments shape the surface. First, this is the intercept-switching parameterization, and one class spans the Krolzig (1997) taxonomy. The regime enters contemporaneously through \(c_{S_t}\), so conditional on the observed lags each regime is linear and inference is a plain \(K\)-state chain – which is what lets estimation ride on a filter with \(K\) states rather than the \(K^{p+1}\) that Hamilton’s original mean-switching form requires; the two coincide at \(p = 0\) and differ in transient dynamics otherwise. Which blocks switch is chosen at construction and MarkovSwitchingARResult.specification reports which member was fitted, I for a switching intercept, A for switching autoregressive coefficients, H for a switching variance; Hamilton’s recession-dating model is MSIH(2)-AR(4), MarkovSwitchingAR(y, order=4, n_regimes=2) here. Second, two identification facts are made explicit rather than left implicit. The likelihood is invariant to permuting regime labels, so a sorting convention is imposed and MarkovSwitchingARResult.label_ordering names it. And the number of regimes cannot be tested by a likelihood ratio: under the null of \(K\) regimes, the parameters of the \((K+1)\)-th and the transition probabilities into it are unidentified, so the statistic has no chi-squared limit. MarkovSwitchingARResult.likelihood_ratio_test() therefore refuses that specific comparison while still permitting tests that hold \(K\) fixed.

Layout. MarkovSwitchingAR validates order and n_regimes through validate_order and the switching flags on the _MarkovSwitchingModel base in _internals; _fit_family draws starts through initial_transition, runs each through _run_em for screen_iter iterations, and refines the best to max_iter. Each EM step builds a _MarkovSwitchingStateSpace in _internals._substrates – the same engine cultivars.state_space.regime_switching exposes – whose filter and smooth are hamilton_filter and kim_smoother from _internals; the M-step state lives in _ExpectationMaximizationState. The packed _MarkovSwitchingFit is assembled by MarkovSwitchingARResult._from_fit(), the result’s state_space rebuilds the substrate for out-of-sample filtering, and simulate runs _simulate_markov_switching. The vector model is cultivars.multivariate.regime_switching.markov_switching; a switching chain over a general state-space measurement is MarkovSwitchingSSM.

References

Hamilton, J. D. (1989). A new approach to the economic analysis of nonstationary time series and the business cycle. Econometrica, 57(2), 357-384.

Hamilton, J. D. (1990). Analysis of time series subject to changes in regime. Journal of Econometrics, 45(1-2), 39-70.

Kim, C.-J. (1994). Dynamic linear models with Markov-switching. Journal of Econometrics, 60(1-2), 1-22.

Hansen, B. E. (1992). The likelihood ratio test under nonstandard conditions: Testing the Markov switching model of GNP. Journal of Applied Econometrics, 7(S1), S61-S82.

Krolzig, H.-M. (1997). Markov-Switching Vector Autoregressions: Modelling, Statistical Inference, and Application to Business Cycle Analysis. Springer.

Example

A latent level shift that no observed-threshold model can see, dated in real time and after the fact:

>>> import numpy as np
>>> from cultivars.univariate.threshold import SETAR
>>> rng = np.random.default_rng(0)
>>> p = np.array([[0.97, 0.03], [0.05, 0.95]])
>>> s = np.zeros(1500, dtype=int)
>>> for t in range(1, 1500):
...     s[t] = np.searchsorted(np.cumsum(p[s[t - 1]]), rng.random())
>>> y = np.array([-1.0, 1.5])[s] + 0.5 * rng.standard_normal(1500)
>>> latent = MarkovSwitchingAR(y, order=1, n_regimes=2).fit(seed=0)
>>> observed = SETAR(y, order=1).fit()
>>> bool(latent.information_criteria.bic < observed.information_criteria.bic - 100)
True
>>> real_time = latent.probabilities("filtered").argmax(axis=1)
>>> after_the_fact = latent.most_likely_regime
>>> bool(np.mean(real_time == s[1:]) > 0.99), bool(np.mean(after_the_fact == s[1:]) > 0.99)
(True, True)

Classes#

MarkovSwitchingAR

Markov-switching autoregression with K latent regimes.

MarkovSwitchingARResult

A fitted Markov-switching autoregression.