我认为你对马尔可夫链及其转移矩阵有一些误解。
首先,你的函数生成的估计转移矩阵是不正确的。为什么呢?我们来复习一下。
离散时间内有N
个不同状态的离散马尔可夫链具有大小为N x N
的转移矩阵P
,其中(i,j)元素是P(X_1 = j | X_0 = i)
,即从状态i
在单个时间步骤中转移到状态j
的概率。
现在,阶数为n
的转移矩阵,表示为P^{n}
,再次是大小为N x N
的矩阵,其中(i,j)元素是P(X_n = j | X_0 = i)
,即在n
个时间步骤中从状态i
转移到状态j
的概率。
一个美妙的结果表明:P^{n} = P^n
,即将单步转移矩阵的n
个幂次相加会得到n
步转移矩阵。
现在,通过这个复习,需要做的就是从给定序列中估计P
,然后可以使用已经估计出的P
来估算P^{n}
,并将矩阵取n
次幂。那么如何估计矩阵P
呢?如果我们将N_{ij}
表示为从状态i
到状态j
的转移观察次数,将N_{i*}
表示为处于状态i
的观察次数,则P_{ij} = N_{ij} / N_{i*}
。
最终Python代码如下:
import numpy as np
def transition_matrix(arr, n=1):
""""
Computes the transition matrix from Markov chain sequence of order `n`.
:param arr: Discrete Markov chain state sequence in discrete time with states in 0, ..., N
:param n: Transition order
"""
M = np.zeros(shape=(max(arr) + 1, max(arr) + 1))
for (i, j) in zip(arr, arr[1:]):
M[i, j] += 1
T = (M.T / M.sum(axis=1)).T
return np.linalg.matrix_power(T, n)
transition_matrix(arr=a, n=1)
>>> array([[0.63636364, 0.18181818, 0.18181818],
>>> [0.4 , 0.4 , 0.2 ],
>>> [0.2 , 0.2 , 0.6 ]])
transition_matrix(arr=a, n=2)
>>> array([[0.51404959, 0.22479339, 0.26115702],
>>> [0.45454545, 0.27272727, 0.27272727],
>>> [0.32727273, 0.23636364, 0.43636364]])
transition_matrix(arr=a, n=3)
>>> array([[0.46927122, 0.23561232, 0.29511645],
>>> [0.45289256, 0.24628099, 0.30082645],
>>> [0.39008264, 0.24132231, 0.36859504]])
有趣的是,当你将顺序n
设置为一个相当高的数字时,矩阵P
的高次幂似乎会收敛到一些非常特定的值。这被称为马尔可夫链的稳态/不变分布,并且它很好地说明了链在长时间/转换期内的行为。此外:
P = transition_matrix(a, 1)
P111 = transition_matrix(a, 111)
print(P)
print(P111.dot(P))
编辑:根据您的评论,我建议使用更高维度的矩阵来表示更高阶的情况,而不是增加行数。一种方法是这样的:
def cal_tr_matrix(arr, order):
_shape = (max(arr) + 1,) * (order + 1)
M = np.zeros(_shape)
for _ind in zip(*[arr[_x:] for _x in range(order + 1)]):
M[_ind] += 1
return M
res1 = cal_tr_matrix(a, 1)
res2 = cal_tr_matrix(a, 2)
现在,res1[i, j]
元素表示发生了多少次i->j的转换,而res2[i, j, k]
元素表示发生了多少次i->j->k的转换。
M = M/M.sum(..)
从for
循环中移除,因为这看起来不正确。 - undefined