本文译自A Brief Introduction to Markovs Chains

译者按:

前面一篇文章讲的是蒙特卡洛积分,也就是通过生成符合特定分布的随机变量来近似计算积分值,例如:

\(E = \int f(x)p(x)dx\)

上面的式子可以理解成求函数 \(f(x)\) 的期望,因此根据大数定理,我们生成符合 \(p(x)\) 分布的 N 个随机变量,然后用:

\(E(f(x))=\frac{\sum\limits_{n=1}^N f(x_n)}{N}\)

来近似计算函数的期望,也就是积分值。但是,如过分布函数 \(p(x)\) 过于复杂,我们是很难生成符合条件的随机变量的,计算机只能生成符合诸如均匀分布,正态分布等简单分布的随机变量,对于复杂分布,我们需要用一些特殊的技巧才能生成其分布,这里就用到马尔可夫链了。本文将首先讲解马尔可夫链的基本定义,以及如何利用一个马尔可夫链来生成随机数。后续的文章将会介绍如何设计马尔可夫链,生成符合我们要求的随机分布。

-------------------------------------------------------------------------------------------------------------------

马尔可夫链是马尔可夫蒙特卡洛方法(MCMC)的关键部分。在 MCMC 方法中,马可科夫链被用来生成符合目标分布的随机变量。为了更好地理解什么是马可科夫链,以及它是如何按照特定分布进行取样的,下面的文章介绍并通过代码实现了几个基本的概念。

马尔可夫链是一个按序列(时间序列)运行的随机过程,在状态空间中(所有可能的状态构成的空间),从一个状态转移到另一个状态:

\(x^{(0)}\rightarrow x^{(1)}\rightarrow x^{(2)} ...\rightarrow x^{(t)}\rightarrow ...\)

一个马尔可夫链由三个元素定义:

1. 一个状态空间 \(x\),这是一个集合,包含了所有可能取到的状态。

2. 一个转移算子 \(p(x^{(t+1)}|x^{(t)})\),定义了从一个状态\(x^{(t)}\)转移到另一个状态\(x^{(t+1)}\)的概率。

3. 一个初始状态分布\(\pi^{0}\) ,定义了在\(t=0\)时,我们取得状态空间中任意一个可能的状态的相应概率。

马尔可夫链从初始状态开始,这个初始状态是按照概率分布\(\pi^{(0)}\) 来抽样得到的,然后按照转移算子 \(p(x^{(t+1)}|x^{(t)})\) 从一个状态转移到另一个状态,依次抽样得到一串序列。

马尔可夫链是无记忆性的,因为它下一个状态的概率仅仅取决于当前的状态,和前面所有状态都无关:

\(p(x^{(t+1)}|x^{(t)},x^{(t-1)}, ...x^{(0)}) = p(x^{(t+1)}|x^{(t)})\)

(这种无记忆的特性正式名称是马尔可夫性质)

如果马尔可夫链的转移算子在转移过程中始终保持不变,那么这个马尔可夫过程就叫做“齐次马尔可夫过程”(time homogenous)。齐次马尔可夫过程的一个非常好的性质是:当马尔可夫链运行了很长时间后,\(t\rightarrow \infty\),这链将会到达一个平衡状态,也叫做平稳分布(stationary distribution):

\(p(x^{(t+1)}|x^{(t)}) = p(x^{(t)}|x^{(t-1)})\)

我们后面将会看到马尔可夫链的平稳分布对取样的重要性,它是马尔可夫蒙特卡洛方法的核心。

有限维空间(齐次)马尔可夫链

如果马尔可夫链的状态空间是有限的离散值,而且它是齐次的,那么转移算子可以被定义为一个矩阵 \(P\),\(P\) 的元素被定义为:

\(P_{i,j}=p(x^{(t+1)}=j|x^{(t)}=i)\)

它的意思是:如果当前的状态是第 i 个状态,那么,它下一个状态转移到状态 j 的概率是 \(P_{i,j}\)。矩阵 \(P\) 的每一行代表状态空间的一个条件概率分布,表示,在已知当前状态为 i 的情况下,下一个状态可以取状态空间中任何值,它们分别对应的概率。

我们接下来看一个有限维空间马尔可夫链的简单例子:

Example: Predicting the weather with a finite state-space Markov chain

假如加州大学伯克利分校的天气有三种:晴天,雾天和雨天(这用来模拟状态空间的三个离散的值)。这里的天气状态十分稳定,所以伯克利的天气预报员可以轻松地根据当前的天气来预测下周的天气,按照下面的规则:

如果今天是晴天,我们有

  \(\bullet\) 下周有很大可能是晴天

    \(\bullet\) \(p(X^{(week)}=sunny|X^{(today)}=sunny) = 0.8\)

  \(\bullet\) 下周有很小的可能下雨

    \(\bullet\) \(p(X^{(week)}=rainy|X^{(today)}=sunny) = 0.05\)

  \(\bullet\) 下周有一定的可能起雾

    \(\bullet\) \(p(X^{(week)}=foggy|X^{(today)}=sunny) = 0.15\)

如果今天是雾天,我们有

  \(\bullet\) 下周有一定可能是晴天

    \(\bullet\) \(p(X^{(week)}=sunny|X^{(today)}=foggy) = 0.4\)

  \(\bullet\) 下周有一定的可能起雾

    \(\bullet\) \(p(X^{(week)}=foggy|X^{(today)}=foggy) = 0.5\)

  \(\bullet\) 下周有较小的可能下雨

    \(\bullet\) \(p(X^{(week)}=rainy|X^{(today)}=foggy) = 0.1\)

如果今天是雨天,我们有

  \(\bullet\) 下周不太可能是晴天

    \(\bullet\) \(p(X^{(week)}=sunny|X^{(today)}=rainy) = 0.1\)

  \(\bullet\) 下周有一定的可能起雾

    \(\bullet\) \(p(X^{(week)}=foggy|X^{(today)}=rainy) = 0.3\)

  \(\bullet\) 下周很有可能继续下雨

    \(\bullet\) \(p(X^{(week)}=rainy|X^{(today)}=foggy) = 0.6\)

所有上面的这些转移规则可以用一个 3*3 的转移矩阵来表示:

P 的每一行表示第 t 次迭代时的天气,每一列表示下周的天气。假如今天是雨天,那么,下周是晴天、两周之后是晴天、乃至6个月后是晴天的概率是多大呢?我们可以通过运行一个初始条件为雨天,转移矩阵为 的马尔可夫链来回答这个问题。下面的 MATLAB 代码实现了这个过程:

  1. % FINITE STATE-SPACE MARKOV CHAIN EXAMPLE
  2.  
  3. % TRANSITION OPERATOR
  4. % S F R
  5. % U O A
  6. % N G I
  7. % N G N
  8. % Y Y Y
  9. P = [.8 .15 .05; % SUNNY
  10. .4 .5 .1; % FOGGY
  11. .1 .3 .6]; % RAINY
  12. nWeeks = 25;
  13.  
  14. % INITIAL STATE IS RAINY
  15. X(1,:) = [0 0 1];
  16.  
  17. % RUN MARKOV CHAIN
  18. for iB = 2:nWeeks
  19. X(iB,:) = X(iB-1,:)*P; % TRANSITION
  20. end
  21.  
  22. % DISPLAY
  23. figure; hold on
  24. h(1) = plot(1:nWeeks,X(:,1),'r','Linewidth',2);
  25. h(2) = plot(1:nWeeks,X(:,2),'k','Linewidth',2);
  26. h(3) = plot(1:nWeeks,X(:,3),'b','Linewidth',2);
  27. h(4) = plot([15 15],[0 1],'g--','Linewidth',2);
  28. hold off
  29. legend(h, {'Sunny','Foggy','Rainy','Burn In'});
  30. xlabel('Week')
  31. ylabel('p(Weather)')
  32. xlim([1,nWeeks]);
  33. ylim([0 1]);
  34.  
  35. % PREDICTIONS
  36. fprintf('\np(weather) in 1 week -->'), disp(X(2,:))
  37. fprintf('\np(weather) in 2 weeks -->'), disp(X(3,:))
  38. fprintf('\np(weather) in 6 months -->'), disp(X(25,:))

 

这里我们可以看到,在第一周,我们得到晴天的概率是0.1,下一周我们得到晴天的概率是0.26,六周以后,晴天的概率为0.6。同时我们注意到,15周之后,马尔可夫链达到一个平衡/稳定的分布,同时有很大的概率得到晴天。这个 15 周的长度被称为马尔可夫链的 burn in 周期,它表示马尔可夫链从初始条件达到稳定分布所需要的迭代次数。

有限状态空间齐次马尔可夫链(finite state-space time-homogeneous Markov chain)的一个很好的性质是,我们不需要真地按顺序跑完所有的迭代从而预测未来的状态。取而代之的是,我们先把转移矩阵乘以 T 次幂,这里 T 表示我们想预测的状态对应的迭代次数(比如上文中的第2周,T 就是2,第三周,就是3,第n周对应的 就是n),然后,用得到的矩阵乘以初始状态 \(\pi^{(0)}\)。例如,为了预测2周后天气情况的概率,已知今天是雨天(i.e, \(\pi^{(0)}=[0,0,1]\)):

\(p(x^{(week2)}) = \pi^{(0)}P^2=[0.26, 0.345, 0.395]\)

6个月后的天气:

\(p(x^{(week24)}) = \pi^{(0)}P^{24}=[0.596, 0.263, 0.140]\)

这和我们按次序运行马尔可夫链得到的结果相同。因此,我们可以通过计算转移矩阵 P 的 T 次幂,把迭代次数 T 设置得很大来近似估计马尔可夫链的稳态分布。同时,也可以用分析的方法来得到马尔可夫链的稳态分布,回忆一下特征向量的定义,可以发现,这里的稳态分布\(\pi\)正是转移矩阵的“左特征向量”:\(\pi\cdot P=\pi\)。同时我们也应该注意到,初始状态的选择并不影响马尔可夫链的稳态分布,也就是说,不管今天是晴天还是下雨还是起雾,经过一段时间的转移后,晴天、雾天、下雨的概率将会趋于一个稳定分布,也就是上例中的\([0.596, 0.263, 0.140]\),读者可以通过 MATLAB 试验一下。

下面的代码是我补充的内容:

上面的代码展示了经过多次迭代后马尔可夫链的分布趋于一个稳态分布。我们将利用马尔可夫链的这一性质进行抽样,从而得到符合这个稳态分布的样例。

之所以讨论MCMC方法,就是为了得到符合某种分布的样例,通常,我们不容易对这种分布进行直接抽样(知道了分布函数也不行),我们计算机只能对均匀分布、正态分布等一系列简单分布进行抽样,对复杂分布是无法抽样的。所以,我们的思路是:构造这样的马尔可夫链,使其稳态分布符合我们要抽样的函数分布,然后沿着马尔可夫链进行抽样,从而得到符合稳态分布的样例,也就是间接地得到了符合目标分布函数的样例。下面我们继续利用上例的转移矩阵,实地抽样,看看得到的样例分布是否符合其稳态分布。代码如下:

  1. % TRANSITION OPERATOR
  2. % S F R
  3. % U O A
  4. % N G I
  5. % N G N
  6. % Y Y Y
  7. P = [.8 .15 .05; % SUNNY
  8. .4 .5 .1; % FOGGY
  9. .1 .3 .6]; % RAINY
  10. nWeeks = 25000; % 为了精确,我们进行25000次抽样
  11. x = zeros(nWeeks,3); % x 用来存储该周天气
  12. p = zeros(nWeeks,3); % p 用来存储到当前周为止,每种天气出现的频率
  13. x(1,:) = [0,0,1]; % 第一周天气为雨天
  14. for iB=2:nWeeks
  15. px = x(iB-1,:)*P; % 根据前一周的天气来计算这一周三种天气出现的概率
  16. % 我们把三种天气的累计频率计算出来,比如px=[0.3,0.5,0.2]
  17. % 那么 cump = [0.3,0.8,1],然后生成01之间符合均匀分布的随机数,
  18. % 这个随机数小于0.3的概率是0.3,大于0.3小于0.8的概率是0.5,大于0.8
  19. % 小于1的概率是0.2,这样就可以模拟随机抽样的过程了
  20. cump = cumsum(px);
  21. % 生成一个在01之间均匀分布的随机数
  22. rnd = rand;
  23. % 看这个随机数落到哪个区间:如果小于第一个数,那么就是晴天,如果在第一个数
  24. % 到第二数个之间,就是雾天,如果在第二个数到第三个数之间,就是雨天
  25. if(rnd<=cump(1))
  26. x(iB,:) = [1,0,0];
  27. elseif(rnd>cump(1)&&rnd<=cump(2))
  28. x(iB,:) = [0,1,0];
  29. else
  30. x(iB,:) = [0,0,1];
  31. end
  32. end
  33. cumx = cumsum(x,1); % 每一行的元素代表到这一周为止,出现的晴天、雾天、雨天的次数
  34. % 每一行各种天气的频数除以当前行对应周数
  35. p = cumx./repmat(transpose(1:nWeeks),1,3);
  36. hold on;
  37. h(1) = plot(1:nWeeks,p(:,1),'r','Linewidth',2);
  38. h(2) = plot(1:nWeeks,p(:,2),'k','Linewidth',2);
  39. h(3) = plot(1:nWeeks,p(:,3),'b','Linewidth',2);
  40. hold off
  41. legend(h, {'Sunny','Foggy','Rainy'});
  42. xlabel('Week')
  43. ylabel('p(Weather)')
  44. xlim([1,nWeeks]);
  45. ylim([0 1]);

我们最后发现,三种天气的抽样分布频率为:0.5987, 0.2626, 0.1387,和马尔可夫链的真实分布 0.596, 0.263, 0.140 十分接近。

注意这个代码和之前的代码的区别,之前的代码是为了得到稳态分布的概率,而这个代码是沿着马尔可夫链进行抽样,然后看最后抽出来的样例是否符合稳态分布。这是MCMC抽样的真实过程,可以总结为:

1. 输入一个初始状态

2. 根据这个初始状态计算下一个取样各种状态可能的概率

3. 生成均匀随机数,看这个随机数落到哪个区间,从而决定下一个状态到底是什么(这就模拟了抽样的过程,有些人以为是取概率最大的那个状态,这是错误的,概率最大的状态也有可能不被抽中,它只是被抽中的概率大而已)

4. 确定了下一个状态后再根据这个状态的值,带入转移矩阵/算子,计算下下个取样各种可能状态的概率

5. 重复步骤2、3,得到一系列的取样,然后扔掉前面马尔可夫链未达到收敛的 burn in,剩下的就是我们的取样。  

连续状态空间马尔可夫链

一个马尔可夫链也可以有实数域上的连续状态空间 \(x\in \mathbb{R}^N\)。这时转移运算符不能够被表示为简单的矩阵,但是,可以表示为实数域上的连续函数。这里需要注意,连续状态空间的马尔可夫链同样有 burn in 周期和稳态分布。得到的稳态分布同样也是连续的(分布函数)。为了更好地理解连续状态空间马尔可夫链如何工作,我们看一个简单的例子。

Example: Sampling from a continuous distribution using continuous state-space Markov chains

我们可以通过连续状态空间的马尔可夫链的稳态分布,来对一个连续概率密度函数取样(通常这个概率密度函数都不容易直接取样,原因是函数太过复杂):我们运行充分次数的马尔可夫链从而让它达到稳态分布,然后保留马尔可夫链到达稳态分布后抽取的样例。

下面的例子里,我们定义一个连续状态空间马尔可夫链。转移算子是正态分布,其方差为1,均值为当前状态与0点的距离的一半,初始状态的分布是均值为0方差为1的标准正态分布。

为了保证链条已经移动得离初始状态足够远,达到了稳态分布,我们将扔掉马尔可夫链最初的50个抽样(也就是 burn in 状态)。我们同时运行多个链,从而更加致密地得到稳态分布抽样。这里我们选择同时运行5个马尔可夫链。

  1. % EXAMPLE OF CONTINUOUS STATE-SPACE MARKOV CHAIN
  2.  
  3. % INITIALIZE
  4. randn('seed',12345)
  5. nBurnin = 50; % # BURNIN
  6. nChains = 5; % # MARKOV CHAINS
  7.  
  8. % DEFINE TRANSITION OPERATOR
  9. % 定义内联函数,用来产生符合正态分布的随机变量normrnd(均值,方差,行,列)
  10. P = inline('normrnd(.5*x,1,1,nChains)','x','nChains');
  11. nTransitions = 1000;
  12. % 将所有状态初始化为0,抽样时对这个矩阵进行更新
  13. x = zeros(nTransitions,nChains);
  14. %初始状态,由于是简单的正态分布,所以可以用函数得到
  15. x(1,:) = randn(1,nChains);
  16.  
  17. % RUN THE CHAINS
  18. for iT = 2:nTransitions
  19. %后一个状态由前一个状态决定,这里源代码等号右边是 P(x(iT-1),nChains)不准确,
  20. %因为5个马尔可夫链上,每个抽样都是由上一个抽样决定的,而不是由第一个链的上一个状态决定
  21. x(iT,:) = P(x(iT-1,:),nChains);
  22. end
  23.  
  24. % DISPLAY BURNIN
  25. figure
  26. subplot(221); plot(x(1:100,:)); hold on;
  27. minn = min(x(:));
  28. maxx = max(x(:));
  29. l = line([nBurnin nBurnin],[minn maxx],'color','k','Linewidth',2);
  30. ylim([minn maxx])
  31. legend(l,'~Burn-in','Location','SouthEast')
  32. title('First 100 Samples'); hold off
  33.  
  34. % DISPLAY ENTIRE MARKOV CHAIN
  35. subplot(223); plot(x);hold on;
  36. l = line([nBurnin nBurnin],[minn maxx],'color','k','Linewidth',2);
  37. legend(l,'~Burn-in','Location','SouthEast')
  38. title('Entire Chain');
  39.  
  40. % DISPLAY SAMPLES FROM STATIONARY DISTRIBUTION
  41. samples = x(nBurnin+1:end,:);
  42. subplot(122);
  43. % 这里 hist 将样例的区间分成100份,返回bins为各个区间的中点,counts是落到各个区间的数目
  44. [counts,bins] = hist(samples(:),100); colormap hot
  45. b = bar(bins,counts);
  46. legend(b,sprintf('Markov Chain\nSamples'));
  47. title(['\mu=',num2str(mean(samples(:))),' \sigma=',num2str(var(samples(:)))])  

  

左上方的输出,我们可以看到1000次转移中的前100次,由5个马尔可夫链同时运行得到。burn in 的切割点用黑线显示。左下方可以看到马尔可夫链的整体转移过程。右边的状态分布直方图,表示 burn in 之后的抽样的分布情况,我们可以发现大部分抽样值都集中在-2到2之间,这个是一个正态分布,均值为0,方差为1.3。

结语

上面的例子中,我们能够根据 burn in 期之后的抽样推断出马尔可夫链的稳态分布。然而,为了能够利用马尔可夫链来对目标分布函数进行抽样,我们需要设计转移算子,使得经过多次迭代后,链最终达到与目标函数吻合的分布。这就是诸多 MCMC 方法,例如 Metropolis sampler,Metropolis-Hastings sampler,以及 Gibbs sampler 所要实现的目标。我们将在后续的文章中对这些基于马尔可夫链的采样方法进行讨论。

A Brief Introduction to Markovs Chains的更多相关文章

  1. HDU 4460 Friend Chains(map + spfa)

    Friend Chains Time Limit : 2000/1000ms (Java/Other)   Memory Limit : 32768/32768K (Java/Other) Total ...

  2. HDOJ 4460 Friend Chains 图的最长路

    类似于树的直径,从随意一个点出发,找到距离该点最远的且度数最少的点. 然后再做一次最短路 Friend Chains Time Limit: 2000/1000 MS (Java/Others)    ...

  3. 代码的坏味道(20)——过度耦合的消息链(Message Chains)

    坏味道--过度耦合的消息链(Message Chains) 特征 消息链的形式类似于:obj.getA().getB().getC(). 问题原因 如果你看到用户向一个对象请求另一个对象,然后再向后者 ...

  4. A chatroom for all! Part 1 - Introduction to Node.js(转发)

    项目组用到了 Node.js,发现下面这篇文章不错.转发一下.原文地址:<原文>. ------------------------------------------- A chatro ...

  5. Introduction to graph theory 图论/脑网络基础

    Source: Connected Brain Figure above: Bullmore E, Sporns O. Complex brain networks: graph theoretica ...

  6. INTRODUCTION TO BIOINFORMATICS

    INTRODUCTION TO BIOINFORMATICS      这套教程源自Youtube,算得上比较完整的生物信息学领域的视频教程,授课内容完整清晰,专题化的讲座形式,细节讲解比国内的京师大 ...

  7. mongoDB index introduction

    索引为mongoDB的查询提供了有效的解决方案,如果没有索引,mongodb必须的扫描文档集中所有记录来match查询条件的记录.然而这些扫描是没有必要,而且每一次操作mongod进程会处理大量的数据 ...

  8. (翻译)《Hands-on Node.js》—— Introduction

    今天开始会和大熊君{{bb}}一起着手翻译node的系列外文书籍,大熊负责翻译<Node.js IN ACTION>一书,而我暂时负责翻译这本<Hands-on Node.js> ...

  9. Introduction of OpenCascade Foundation Classes

    Introduction of OpenCascade Foundation Classes Open CASCADE基础类简介 eryar@163.com 一.简介 1. 基础类概述 Foundat ...

随机推荐

  1. Selenium Web 自动化 - 项目实战(三)

    Selenium Web 自动化 - 项目实战(三) 2016-08-10 目录 1 关键字驱动概述2 框架更改总览3 框架更改详解  3.1 解析新增页面目录  3.2 解析新增测试用例目录  3. ...

  2. 剑指offer二:替换空格

    题目描述: 请实现一个函数,将一个字符串中的空格替换成"%20".例如,当字符串为We Are Happy.则经过替换之后的字符串为We%20Are%20Happy. 解题思路: ...

  3. HTML表格与列表

    HTML表格 表格其实就是很多的小单元格,而这些小单元格很有次序的排列着,它们有很多行,很多列.这些很多行列组成的东西,就叫表格,表格是<table>标签来定义的.而<table&g ...

  4. http知识

    http请求的过程:客户端发起请求,创建端口:http服务器在端口监听客户端请求:http服务器向客户端返回状态和内容. 浏览器搜索自身的DNS缓存-->搜索操作系统自身的DNS缓存(浏览器没有 ...

  5. D3.js 力导向图

    花了大半天看了一个八十几行的代码..心累 力导向图是之前就有画过很多次的东西,但是这次的代码看上去很陌生,然后发现是D3更新了4.0.... 先贴代码 var svg = d3.select(&quo ...

  6. 根据多年经验整理的《互联网MySQL开发规范》

    一.基础规范 使用 INNODB 存储引擎 表字符集使用 UTF8  所有表都需要添加注释 单表数据量建议控制在 5000W 以内 不在数据库中存储图⽚.文件等大数据 禁止在线上做数据库压力测试 禁⽌ ...

  7. 【HDU5955】Guessing the Dice Roll/马尔科夫

    先从阿里机器学习算法岗网络笔试题说起:甲乙两人进行一个猜硬币的游戏.每个人有一个目标序列,由裁判来抛硬币.谁先得到裁判抛出的一串连续结果,谁赢. 甲的目标序列是正正正,乙的目标序列是反正正.那么如果裁 ...

  8. php 判断是手机版还是电脑端

    function isMobile() { // 如果有HTTP_X_WAP_PROFILE则一定是移动设备 if (isset ($_SERVER['HTTP_X_WAP_PROFILE'])) { ...

  9. Android之打log

    Android之打log 1.在代码中加上自己的log 2,模块编译mm -B或者./mk mm/mmm packages/apps/Contacts/ 3编译成功后install或者push生成的a ...

  10. Java里正则表达式

    java.util.regex是一个用正则表达式所订制的模式来对字符串进行匹配工作的类库包.它包括两个类:Pattern和Matcher Pattern 一个Pattern是一个正则表达式经编译后的表 ...