DiscreteMarkovChain#
- class pymc_extras.distributions.DiscreteMarkovChain(*args, steps=None, n_lags=1, **kwargs)[source]#
A Discrete Markov Chain is a sequence of random variables
\[\{x_t\}_{t=0}^T\]Where transition probability \(P(x_t | x_{t-1})\) depends only on the state of the system at \(x_{t-1}\). With
n_lags > 1the chain is of higher order, and the transition probability \(P(x_t | x_{t-1}, \dots, x_{t-n\_lags})\) depends on the lastn_lagsstates.- Parameters:
P (tensor) –
Matrix of transition probabilities between states. Rows must sum to 1. One of P or P_logits must be provided.
When
time_varying_P=False(default),Pis ak x kmatrix shared across all transitions, with optional leading batch dimensions:(*batch, k, k).When
time_varying_P=True,Pcarries an extra time axis just before the two state axes:(*batch, steps, k, k).P[..., t, :, :]is the transition matrix used to go from statetto statet + 1, so the time axis must have lengthsteps(one transition matrix per step). Whenstepsis not given explicitly, it is inferred from this axis.With
n_lags > 1the two state axes becomen_lags + 1axes, all of lengthk:P[..., x_{t-n_lags}, ..., x_{t-1}, x_t], so the shape is(*batch, k, ..., k)(or(*batch, steps, k, ..., k)when time-varying).P_logit (tensor, optional) – Matrix of transition logits. Converted to probabilities via Softmax activation. One of P or P_logits must be provided.
steps (tensor, optional) – Length of the markov chain. Only needed if state is not provided.
init_dist (unnamed distribution, optional) –
Distribution over the
n_lagsinitial states. Unnamed refers to distributions created with the.dist()API. A scalar-support distribution (e.g.Categorical) is broadcast IID across the initial states; a vector-support distribution (e.g.JointCategorical) provides their joint distribution and must have support lengthn_lags.Warning
init_dist will be cloned, rendering it independent of the one passed as input.
n_lags (int, default 1) – Order of the chain: how many previous states the transition probability conditions on.
Pgains one state axis per extra lag (seePabove) and the chain starts fromn_lagsinitial states drawn frominit_dist, so it hasn_lags + stepsstates in total.time_varying_P (bool, default False) – If
True,Pis interpreted as a sequence of transition matrices, one per step, with shape(*batch, steps, k, k)(seePabove). This disambiguates the time axis from a leading batch dimension.
Notes
The initial distribution will be cloned, rendering it distinct from the one passed as input.
Examples
Create a Markov Chain of length 100 with 3 states. The number of states is given by the shape of P, 3 in this case.
import numpy as np import pymc as pm import pymc_extras as pmx with pm.Model() as markov_chain: P = pm.Dirichlet("P", a=[1, 1, 1], size=(3,)) init_dist = pm.Categorical.dist(p=np.full(3, 1 / 3)) markov_chain = pmx.DiscreteMarkovChain( "markov_chain", P=P, init_dist=init_dist, shape=(100,) )
Use a time-varying transition matrix.
Pcarries a leading time axis of lengthsteps(here 99 transitions for a chain of 100 states), so its shape is(steps, k, k). Below the chain switches regime partway through: a “sticky” kernel governs the first 40 transitions and a “mixing” kernel the remaining 59, assembled by repeating each kernel along the time axis.import numpy as np import pymc as pm import pymc_extras as pmx import pytensor.tensor as pt with pm.Model() as regime_chain: # Two 2 x 2 kernels: states persist under "sticky", shuffle under "mixing". P_sticky = pm.Dirichlet("P_sticky", a=np.eye(2) * 8 + 1, size=2) P_mixing = pm.Dirichlet("P_mixing", a=np.ones((2, 2)), size=2) # Stack one kernel per step: 40 sticky then 59 mixing -> shape (99, 2, 2) P = pt.concatenate( [pt.repeat(P_sticky[None], 40, axis=0), pt.repeat(P_mixing[None], 59, axis=0)], axis=0, ) init_dist = pm.Categorical.dist(p=np.full(2, 0.5)) markov_chain = pmx.DiscreteMarkovChain( "markov_chain", P=P, init_dist=init_dist, time_varying_P=True, shape=(100,), )
Use a second-order chain, where each state depends on the previous two.
Pgains one state axis per lag, so it is(2, 2, 2)here:P[x_{t-2}, x_{t-1}, x_t]. The chain starts fromn_lags=2initial states, soshape=(100,)means 98 transitions.import numpy as np import pymc as pm import pymc_extras as pmx with pm.Model() as second_order_chain: P = pm.Dirichlet("P", a=np.ones((2, 2, 2))) init_dist = pm.Categorical.dist(p=np.full(2, 0.5)) markov_chain = pmx.DiscreteMarkovChain( "markov_chain", P=P, init_dist=init_dist, n_lags=2, shape=(100,), )
- __init__()#
Methods
__init__()dist([P, logit_P, steps, init_dist, n_lags, ...])Create a tensor variable corresponding to the cls distribution.
rv_op(P, steps, init_dist, n_lags[, size, ...])The type of the None singleton.