马尔可夫性
马尔可夫性也叫做无后效性、无记忆性,即是过去只能影响现在,不能影响将来。
在数学上,如果为一个随机过程,则马科尔夫性质可以符号化成如下形式:
从上式可知,过去(s)并不影响将来(t+h)的状态,但当前状态蕴含着以往所有的状态信息。
符号“y|X(t)”通常表示给定变量 X 在时间 t 的值时变量 y 的条件概率分布。它表明 y 的值取决于特定时间 t 的 X 值。
马尔可夫过程
若随机过程满足马尔可夫性,则称为马尔可夫过程。 在该模型中,存在两个假设:
1、随机过程满足马尔可夫性性;
2、状态转换矩阵不随时间的变化而变化。
该模型的流程如下:
马尔可夫过程流程
马尔可夫链
时间和状态都是离散型的马尔可夫过程称为马尔可夫链,又称离散时间马尔可夫链(Discrete-time Markov Chain)。
对于,对任意状态以及成立:
基本要素
- 状态空间:表示随机过程在n时刻处在i状态,所有状态的取值构成的集合称为“状态空间”,以符号 I 表示。
- 转移概率:把在当前时刻状态到下一时刻某状态的条件概率称作转移概率。
以上式子表示状态i到状态j的转移概率。
- 转移概率矩阵: 由于每个时刻状态不止一种,我们将所有状态之间的转移概率组成一个矩阵,这个矩阵可以称为“转移概率矩阵”,该矩阵大小为。状态转移矩阵不随时间的变化。
- 初始状态: 还是以上述基金为例子,假设在第一天基金的变动情况分布如下:
此时为初始分布,即�0=(�0(1),�0(2),�0(3))=(0.3,0.4,0.3),其中��(�)=�(��=�),�=1,2,3,则有�1=�0∗�,��=�0∗��。
- 转移方程: 对于m步转移,则有转移方程如下:
���(�+�)=∑�=1����(�)���(�)
今天 状态分布 �0=(0.3,0.4,0.3) 明天 状态分布 �1=�0∗� 后天 状态分布 �2=�1∗� 大后天 状态分布 �3=�2∗�
这时候马尔可夫链可视化如下,可见下一个节点状态仅受上一个节点的状态及状态转移矩阵的影响。
隐马尔可夫模型
在正常的马尔可夫模型中,仅包含一个随机过程,我们需要预测的状态就是观察者可以直接看到的状态序列。但在隐马尔可夫模型中,具有双随机过程:状态-状态转移和状态-输出发散,其流程图如下:
HMM模型流程
引用维基百科上一个例子,存在乡村诊所,村民有着非常理想化的特性,要么健康要么发烧。他们只有问诊所的医生的才能知道是否发烧。聪明的医生通过询问病人的感觉诊断他们是否发烧。村民只回答他们感觉正常、头晕或冷。
假设一个病人每天来到诊所并告诉医生他的感觉。医生相信病人的健康状况如同一个离散马尔可夫链。病人的状态有两种“健康”和“发烧”,但医生不能直接观察到,这意味着状态对他是“隐含”的。每天病人会告诉医生自己有以下几种由他的健康状态决定的感觉的一种:正常、冷或头晕。病人连续三天看医生,医生发现第一天他感觉正常,第二天感觉冷,第三天感觉头晕,这些是观察结果。整个系统可以为一个隐马尔可夫模型(HMM)。
作为一个统计模型,它用来描述一个含有隐含位置参数的马尔可夫过程。其重点和难点在于从观测的参数(显状态)中确定该过程的隐含参数(隐状态)。因此,我们在原来的马尔可夫过程的基础假设上加入假设:显状态仅与当前隐状态有关。对于这个假设,可以理解为病人向医生表述其头晕症状,那么这个症状仅与他当前的病源(健康、发烧)有关。
基本要素
在明确隐马尔可夫模型的定义以后,我们得到隐马尔可夫模型的五项基本要素,可以概括为五元组�=(�,�,�,�,�):
- S:隐含状态集合。
- N:观察状态集合。
- A:隐藏状态间的转移概率矩阵。
- B:隐-显状态发散矩阵(即隐藏状态到输出状态的概率)。
- PI:初始概率分布(隐藏状态的初始概率分布)。
基本问题
隐马尔可夫模型简称为HMM(Hiden Markov Model),主要应用于以下三种典型问题:
- 已知模型参数和某一特定输出序列,求最后时刻各个隐含状态的概率分布。(预测) 求解目标:
�(�(�)|�(1),……,�(�))
假设,在时刻�,状态为�时,前面的时刻观测到�(1),……,�(�)的概率,记为α�(�),并称之为前向概率:
��(�)=�(�(1),……,�(�),��=�|λ)
当�=1时,输出为�(1),�(1)可能是由任意一个隐状态发出,即:
�(�(1)|λ)=��1∗�1(�(1))+��2∗�2(�(1))=�1(1)+�2(1)
在上述例子中,病人第一天告知医生为"正常"的状态,则α1(1)计算的前向概率表示到第一天为止观测病人为正常的,且其状态为“健康”的概率。 当�=2时,输出为、�(1)、�(2),经过推理可知:
�(�(1)�(2)|λ)=�(�(1)�(2),�2=�1|λ)+�(�(1)�(2),�2=�2|λ)=�1(1)∗�1(12)�1(�(2))+�1(2)�2(12)�1(�(2))=�1(2)+�2(2)
递推求取前向概率和观测序列概率,则有:
��+1(�)=[∑�=1���(�)���]��(��+1),�=1,2,3,……,�−1
�(�(�)|�(1),……,�(�))=�(�(1),……,�(�)|�)=∑�=1���(�)
其中 ∑�=1���(�)��� 表示上层所有节点到当前层节点的连接, ��(��+1) 为隐状态-显状态发散概率。
前向算法的代码定义如下:
def Forward(trainsition_probability,emission_probability,pi,obs_seq):
"""
:param trainsition_probability:是状态转移矩阵
:param emission_probability:发射矩阵
:param pi: pi是初始状态概率
:param obs_seq: obs_seq是观察状态序列
:return: 返回结果
"""
trainsition_probability = np.array(trainsition_probability)
emission_probability = np.array(emission_probability)
print emission_probability[:,0]
pi = np.array(pi)
Row = np.array(trainsition_probability).shape[0]
F = np.zeros((Row,Col)) #最后要返回的就是F,就是我们公式中的alpha
F[:,0] = pi * np.transpose(emission_probability[:,obs_seq[0]]) #这是初始化求第一列,就是初始的概率*各自的发射概率
print F[:,0]
for t in range(1,len(obs_seq)): #这里相当于填矩阵的元素值
for n in range(Row): #n是代表隐藏状态的
F[n,t] = np.dot(F[:,t-1],trainsition_probability[:,n])*emission_probability[n,obs_seq[t]] #对应于公式,前面是对应相乘
return F
2. 已知模型参数和某一特定输出序列,求中间时刻各个隐含状态的概率分布。(平滑)
求解目标:
<�(�(�)|�(1),……,�(�)),�<�
首先初始化后向概率,记为 ��(�)=1,�=1,2,3,……,� 。即假设观到该 � 时刻的输出序列时,所有的状态的后向概率都为1。可以理解为从 �+1 到 � 时刻的部分观测序列并不存在(不必考虑),因此规定 ��(�) 的值为1。
对于 �=�−1,�−2,……,1 ,有表达式:
��(�)=∑�=1������(��+1)��+1(�),�=1,2,3,……,�
其中,���为隐状态转移矩阵,��(��+1)为隐状态-显状态发散概率,��+1(�)为�后面序列对应的后向概率。可以理解为,若要求当前层的某个结点的后向概率,相当于其后面一层的所有结点转移到该层结点上。
结合前面介绍的前向算法,第�时刻的第�个状态的概率为�时刻的前向和后向概率相乘,即:
�(��=�1,�(1),……,�(�)|�)=��(�)��(�)
则有:
�(�(�)|�(1),……,�(�))=∑�=1���(�)��(�)
后向算法Python代码实现如下:
def Backward(trainsition_probability,emission_probability,pi,obs_seq):
"""
:param trainsition_probability:状态转移矩阵
:param emission_probability:是发射矩阵
:param pi:是初始状态概率
:param obs_seq:观察状态序列
:return: 返回结果
"""
trainsition_probability = np.array(trainsition_probability)
emission_probability = np.array(emission_probability)
pi = np.array(pi) #要进行矩阵运算,先变为array类型
Row = trainsition_probability.shape[0]
Col = len(obs_seq)
F = np.zeros((Row,Col))
F[:,(Col-1):] = 1 #最后的每一个元素赋值为1
for t in reversed(range(Col-1)):
for n in range(Row):
F[n,t] = np.sum(F[:,t+1]*trainsition_probability[n,:]*emission_probability[:,obs_seq[t+1]])
return F
3. 已知模型参数和某一特定输出序列,寻找最可能的能产生某一特定输出序列的隐含状态的序列。(解码)
求解目标:
�([�(1),……,�(�)]|[�(1),……,�(�)])
在给病人看病的过程中,医生产生了一个问题:怎样的健康状态序列最能够解释这些观察结果。
求解该问题的模型为:Viterbi模型,其核心过程符号化如下:
�(����������)=�(�1)∗�(�1|�1)∏�=2��(��|��−1)�(��|��)
其中,�(�1)是初始状态(即医生假设的身体状态分布),�(�1|�1)是第一天的观测状态,即病人第一天说自己是“正常”对应的概率最大的隐状态。我们要递推求取概率最大的finalstate,最后求得的结果就是最大可能的隐状态对应的概率。
Viterbi算法Python代码实现如下:
def viterbi(obs, states, start_p, trans_p, h2o_p): # Viterbi算法
"""
:param obs:观察状态序列
:param start:隐含状态
:param start_p:隐状态转移矩阵
:param trans_p:状态转移矩阵
:param h2o_p:是发射矩阵
:return: 返回结果
"""
V = [{}]
path = {
for y in states:
V[0][y] = start_p[y] * h2o_p[y][obs[0]]
# 初始状态,由start的概率,对应乘上发射概率,即由隐状态到观测状态的可能性
path[y] = [y] # 记录下相应的路径
for t in range(1,len(obs)):
V.append({})
newpath = {}
for y in states:
# 对于每个状态,计算其由前一天的各个状态,到达今天的y的概率大小,与y0自身相比较,取最大值
# 前一天到达今天的每个状态对应的路径大小都计算了,取最大值。作为V[t][y]的值,并更新路径
(prob, state) = max([(V[t-1][y0] * trans_p[y0][y] * h2o_p[y][obs[t]], y0) for y0 in states])
V[t][y] = prob
newpath[y] = path[state] + [y]
path = newpath
print_dptable(V)
(prob, state) = max([(V[len(obs) - 1][y], y) for y in states])
return (prob, path[state])
总结
在这片文章中,我们整理了三种马尔可夫模型(马尔可夫过程、马尔可夫链、HMM)以及相关的基础知识。加深对模型的理解和深化,以便于进一步的应用。归根结底,马尔可夫模型是一类描述当前时刻的状态仅由前一个时刻的状态影响的统计模型。
最后附上源于网络的一句“小鸡汤”,共勉!
-Life is like a Markov chain, your future only depends on what you are doing now, and independent of your past.
-人生就像是一个马尔可夫链,你的未来取决于你当下正在做的事,而无关于过去。
图源网络
参考资料
1、PyMC :马尔可夫链蒙特卡洛采样工具包:https://github.com/pymc-devs/pymc3
2、《马尔可夫与隐马尔可夫模型》:马尔可夫与隐马尔可夫模型 - 知乎
3、Viterbi algorithm:https://github.com/hankcs/Viterbi
编辑于 2021-07-19 14:06