⚠️ Alpha内测版本警告:此为早期内部构建版本,尚不完整且可能存在错误,欢迎大家提Issue反馈问题或建议。
Skip to content

第19章 马尔可夫链蒙特卡罗法

习题19.1

  用蒙特卡罗积分法求

x2exp(x22)dx

解答:

解答思路:

  1. 给出蒙特卡罗积分计算方法。
  2. 将被积分的函数分解,得到其数学期望表示形式。
  3. 自编程实现,使用样本均值求近似计算积分。

解答步骤

第1步:蒙特卡罗积分计算方法

  根据书中第19.1.3节的关于蒙特卡罗积分法的描述:

  假设有一个函数 h(x),目标是计算该函数的积分

Xh(x)dx

  如果能够将函数 h(x) 分解成一个函数 f(x) 和一个概率密度函数 p(x) 的乘积的形式, 那么就有

Xh(x)dx=Xf(x)p(x)dx=Ep(x)[f(x)]

于是函数 h(x) 的积分可以表示为函数 f(x) 关于概率密度函数 p(x) 的数学期望。实际上, 给定一个概率密度函数 p(x), 只要取 f(x)=h(x)p(x),就可得上式。就是说, 任何一个函数的积分都可以表示为某一个函数的数学期望的形式。而函数的数学期望又可以通过函数的样本均值估计。于是,就可以利用样本均值来近似计算积分。

Xh(x)dx=Ep(x)[f(x)]1ni=1nf(xi)

第2步:将所积分的函数分解,其得到数学期望表示形式

  取概率密度函数为标准正态分布的密度函数 p(x)=12πexp(x22),则

f(x)=h(x)p(x)=x2exp(x22)12πexp(x22)=2πx2

  将原函数积分表示为函数 f(x) 关于概率密度函数 p(x) 的数学期望

Xx2exp(x22)dx=Xf(x)p(x)dx=Ep(x)[f(x)]

第3步:自编程实现,使用样本均值求近似计算积分

python
import numpy as np


class MonteCarloIntegration:
    def __init__(self, func_f, func_p):
        # 所求期望的函数
        self.func_f = func_f
        # 抽样分布的概率密度函数
        self.func_p = func_p

    def solve(self, num_samples):
        """
        蒙特卡罗积分法
        :param num_samples: 抽样样本数量
        :return: 样本的函数均值
        """
        samples = self.func_p(num_samples)
        vfunc_f = lambda x: self.func_f(x)
        vfunc_f = np.vectorize(vfunc_f)
        y = vfunc_f(samples)
        return np.sum(y) / num_samples
python
def func_f(x):
    """定义函数f"""
    return x ** 2 * np.sqrt(2 * np.pi)


def func_p(n):
    """定义在分布上随机抽样的函数g"""
    return np.random.standard_normal(int(n))


# 设置样本数量
num_samples = 1e6

# 使用蒙特卡罗积分法进行求解
monte_carlo_integration = MonteCarloIntegration(func_f, func_p)
result = monte_carlo_integration.solve(num_samples)
print("抽样样本数量:", num_samples)
print("近似解:", result)
抽样样本数量: 1000000.0
近似解: 2.5071535842506965

习题19.2

  证明如果马尔可夫链是不可约的,且有一个状态是非周期的,则其他所有状态也是非周期的,即这个马尔可夫链是非周期的。

解答:

解答思路:

  1. 给出马尔科夫链的基本定义
  2. 给出不可约的定义
  3. 给出非周期的定义
  4. 证明如果马尔可夫链是不可约的,则所有状态周期都相同
  5. 证明原命题

解答步骤:

第1步:马尔可夫链

  根据书中第19章的定义19.1马尔科夫链的基本定义:

定义19.1(马尔科夫链) 考虑一个随机变量的序列X={X0,X1,,Xt,},这里Xt表示时刻t的随机变量,t=0,1,2,。每个随机变量Xt(t=0,1,2,)的取值集合相同,称为状态空间,表示为S。随机变量可以是离散的,也可以是连续的。以上随机变量的序列构成随机过程(stochastic process)。

  假设在时刻0的随机变量X0遵循概率分布P(X0)=π0,称为初始状态分布。在某个时刻t1的随机变量Xt与前一时刻的随机变量Xt1之间有条件分布P(Xt|Xt1),如果Xt只依赖于Xt1,而不依赖于过去的随机变量{X0,X1,,Xt2},这一性质称为马尔可夫性,即

P(Xt|X0,X1,,Xt1)=P(Xt|Xt1),t=1,2,

具有马尔可夫性的随机序列X={X0,X1,,Xt,}称为马尔可夫链,或马尔可夫过程。条件概率分布P(Xt|Xt1)称为马尔可夫链的转移概率分布。转移概率分布决定了马尔可夫链的特性。

  根据书中第19.2.2节的状态转移概率:

Pijt=P(Xt=i|X0=j)

表示时刻0从状态j出发,时刻t到达状态it步转移概率。

第2步:不可约的定义

  根据书中第19章的定义19.3的不可约的定义:

  定义19.3(不可约) 设有马尔可夫链 X={X0,X1,,Xt,},状态空间为 S,对于任意状态 i,jS,如果存在一个时刻 t(t>0) 满足

P(Xt=i|X0=j)>0

也就是说,时刻0从状态 j 出发, 时刻 t 到达状态 i 的概率大于0,则称此马尔可夫链 X 是不可约的(irreducible),否则称马尔可夫链是可约的(reducible)。

第3步:非周期的定义

  根据书中第19章的定义19.4的非周期的定义:

定义19.4(非周期) 设有马尔可夫链 X={X0,X1,,Xt,},状态空间为 S,对于任意状态 iS,如果时刻0从状态 i 出发,t 时刻返回状态的所有时间长 {t:P(Xt=i|X0=i)>0} 的最大公约数是1,则称此马尔可夫链 X 是非周期的(aperiodic),否则称马尔可夫链是周期的(periodic)。

第4步:证明如果马尔可夫链是不可约的,则所有状态周期都相同

  如果该马尔可夫链是不可约的,则对于 i,jS,必然存在时刻 m,n(m>0,n>0) 满足

pijm>0,pjin>0

根据状态转移概率的定义,有 pijm=P(Xm=i|X0=j),pjin=P(Xn=j|X0=i)

  可得

piim+n=kSpikmpkinpijmpjin>0

  则必然存在 s 使得 Pjjs>0,且满足

Piim+n+sPijmPjjsPjin>0

  假设状态 i,j 的周期分别是 d(i),d(j),由上两式可知

(m+n)modd(i)=0(m+n+s)modd(i)=0

  所以 smodd(i)=0

  又因为 Pjjs>0,所以 smodd(j)=0。因此 d(i)modd(j)=0。同理可得 d(j)modd(i)=0

  故 d(i)==d(j),可得如果马尔可夫链是不可约的,所有状态周期都是相同的。

第5步:证明原命题

  在不可约的马尔可夫链中如果有一个状态的是非周期的,即其周期为1,则其他所有状态的周期也为1,所以该马尔可夫链是非周期的。原命题得证。

习题19.3

  验证具有以下转移概率矩阵的马尔可夫链是可约的,但是非周期的。

P=[1/21/2001/201/2001/200001/21]

解答:

解答思路:

  1. 给出平稳分布的定义
  2. 计算该马尔可夫链的平稳分布
  3. 验证该马尔可夫链是可约的
  4. 验证该马尔可夫链是非周期的

解答步骤:

第1步:平稳分布的定义

  根据书中第19章的定义19.2的平稳分布的定义:

  定义19.2(平稳分布) 设有马尔可夫链 X={X0,X1,,Xt,},其状态空间为 S,转移概率矩阵为 P=(pij),如果存在状态空间 S 上的一个分布

π=[π1π2]

使得

π=Pπ

则称 π 为马尔可夫链 X={X0,X1,,Xt,} 的平稳分布。

  根据书中第19章的引理19.1:

  引理19.1 给定一个马尔可夫链 $ X = {X_0, X_1, \cdots, X_t, \cdots }$,状态空间为 S,转移概率矩阵为 P=(pij),则分布 π=(π1,π2,)TX 的平稳分布的充分必要条件是 $ \pi = (\pi_1, \pi_2, \cdots )^T$ 是下列方程组的解:

xi=jpijxj,i=1,2,xi0,i=1,2,ixi=1

第2步:计算该马尔可夫链的平稳分布

  设平稳分布为 π=(x1,x2,x3,x4)T,则由引理19.1可得

x1=12x1+12x2x2=12x1+12x3x3=12x2x4=12x3+1x4x1+x2+x3+x4=1xi0,i=1,2,3,4

解方程组,得到唯一的平稳分布

π=(0,0,0,1)T

第3步:验证该马尔可夫链是不可约的

  此马尔可夫链,转移到状态4后,就在该状态上循环跳转,不能到达状态1、状态2和状态3,最后停留在状态4,故该马尔可夫链是可约的。

第4步:验证该马尔可夫链是非周期的

  1. 对于状态1,它返回状态1的最小时间长为1,故其所有时间长的最大公约数是1;
  2. 对于状态2,它通过212返回状态2的时间长为2,通过2112返回状态2的时间长为3,故其所有时间长的最大公约数是1
  3. 对于状态3,它通过323返回状态3的时间长为2,通过321123返回状态3的时间长为5,故其所有时间长的最大公约数是1
  4. 对于状态4,它返回状态4的最小时间长为1,故其所有时间长的最大公约数是1

综上,该马尔可夫链是非周期的。

习题19.4

  验证具有以下转移概率矩阵的马尔可夫链是不可约的,但是周期性的。

P=[01/200101/2001/201001/20]

解答:

解答思路:

  1. 计算该马尔可夫链的平稳分布
  2. 验证该马尔可夫链是不可约的
  3. 验证该马尔可夫链是周期性的

解答步骤:

第1步:计算该马尔可夫链的平稳分布

  根据书中第19章的定义19.2的平稳分布的定义和引理19.1(同习题19.4),设平稳分布为 π=(x1,x2,x3,x4)T,则由引理19.1可得:

x1=12x2x2=1x1+12x3x3=12x2+1x4x4=12x3x1+x2+x3+x4=1xi0,i=1,2,3,4

解方程组,得到唯一的平稳分布

π=(16,13,13,16)T

第2步:验证该马尔可夫链是不可约的

  观察到平稳分布各项均大于0,说明此马尔可夫链从任意状态出发,经过若干步之后,可以到达任意状态,故该马尔可夫链是不可约的。

第3步:验证该马尔可夫链是周期性的

  该马尔可夫链的转移仅发生在相邻奇偶状态之间,从每个状态出发,返回该状态的时刻都是2的倍数:{2,4,6,,2n},nN。故该马尔可夫链是周期性的,其周期为2。

习题19.5

  证明可逆马尔可夫链一定是不可约的。

解答:

解答思路

  1. 给出可逆马尔可夫链的定义
  2. 构造特殊的可逆马尔可夫链
  3. 验证其是可约的,原命题不成立

解答步骤

第1步:可逆马尔可夫链

  根据书中第19章的定义19.6的可逆马尔可夫链的定义:

  定义19.6(可逆马尔可夫链) 设有马尔可夫链 $ X = {X_0, X_1, \cdots, X_t, \cdots }$,状态空间为 S,转移概率矩阵为 P,如果有状态分布 π=(π1,π2,)T,对于任意状态 i,jS,对任意一个时刻 t 满足

P(Xt=i|Xt1=j)πj=P(Xt1=j|Xt=i)πi,i,j=1,2,

或简写为

pjiπj=pijπi,i,j=1,2,

则称此马尔可夫链 X 为可逆马尔可夫链,上式称为细致平衡方程。

第2步:构造特殊的可逆马尔可夫链

  对于以单位矩阵做转移矩阵的马尔可夫链,其转移矩阵P

P=[1000100001]

  对于任意平稳分布 π,满足Pπ=π 恒成立,所以该马尔可夫链是可逆的。

第3步:验证其是可约的,原命题被证伪

  对于任意状态 iS,跳转到其他的状态 jS(ji) 的概率始终为0,即 pi,jt=0,tN。所以该马尔可夫链是可约的。

  这与原命题矛盾,故原命题不成立。

习题19.6

  从一般的Metropolis-Hastings算法推导出单分量Metropolis-Hastings算法。

解答:

解答思路:

  1. 给出一般的Metropolis-Hastings算法
  2. 给出单分量Metropolis-Hastings算法的基本思想
  3. 推导单分量Metropolis-Hastings算法

解答步骤:

第1步:一般的Metropolis-Hastings算法

  根据书中第19章的算法19.2的Metropolis-Hastings算法:

算法19.2(Metropolis-Hastings算法)
输入:抽样的目标分布的密度函数p(x),函数f(x)
输出:p(x)的随机样本xm+1,xm+2,,xn,函数样本均值fmn
参数:收敛步数m,迭代步数n
(1)任意选择一个初始值x0
(2) 对 i=1,2,,n循环执行
  (a)设状态xi1=x,按照建议分布q(x,x)随机抽取一个候选状态x
  (b)计算接受概率

α(x,x)=min{1,p(x)q(x,x)p(x)q(x,x)}

  (c)从区间(0,1)中按均匀分布随机抽取一个数u
     若 uα(x,x),则状态 xi=x;否则,状态 xi=x
(3)得到样本集合 $ { x_{m+1}, x_{m+2}, \cdots, x_n }$
计算

fmn=1nmi=m+1nf(xi)

2. 理解单分量 Metropolis-Hastings 算法的基本思想

  根据书中第19.4.3节的单分量Metropolis-Hastings算法:

  在 Metropolis-Hastings 算法中,通常需要对多元变量分布进行抽样,有时对多元变量分布的抽样是困难的。可以对多元变量的每一变量的条件分布依次分别进行抽样,从而实现对整个多元变量的一次抽样, 这就是单分量 Metropolis-Hastings 算法。
  假设马尔可夫链的状态由 k 维随机变量表示

x=(x1,x2,,xk)T

其中 xj 表示随机变量 x 的第 j 个分量,j=1,2,,k,而 x(i) 表示马尔可夫链在时刻 i 的状态

x(i)=(x1(i),x2(i),,xk(i))T,i=1,2,,n

其中 xj(i) 是随机变量 x(i) 的第 j 个分量,j=1,2,,k
  为了生成容量为 n 的样本集合 {x(1),x(2),,x(n)},单分量 Metropolis-Hastings 算法由下面的 k 步迭代实现 Metropolis-Hastings 算法的一次迭代。
  设在第 (i1) 次迭代结束时分量 xj 的取值为 xj(i1),在第 i 次迭代的第 j 步,对分量 xj 根据 Metropolis-Hastings 算法更新,得到其新的取值 xj(i)。首先,由建议分布 q(xj(i1),xj|xj(i)) 抽样产生分量 xj 的候选值 xj(i),这里 xj(i) 表示在第 i 次迭代的第 (j1) 步后的 x(i) 除去 xj(i1) 的所有值,即

xj(i)=(x1(i),,xj1(i),xj+1(i1),,xk(i1))T

其中分量 1,2,,j1 已经更新。然后,按照接受概率

α(xj(i1),xj(i)|xj(i))=min{1,p(xj(i)|xj(i))q(xj(i),xj(i1)|xj(i))p(xj(i1)|xj(i))q(xj(i1),xj(i)|xj(i))}

抽样决定是否接受候选值 xj(i) 。如果 xj(i) 被接受,则令 xj(i)=xj(i);否则令 xj(i)=xj(i1)。其余分量在第 j 步不改变。马尔可夫链的转移概率为

p(xj(i1),xj(i)|xj(i))=α(xj(i1),xj(i)|xj(i))q(xj(i1),xj(i)|xj(i))

3. 推导单分量 Metropolis-Hastings 算法

单分量 Metropolis-Hastings 算法
输入:抽样的目标分布的密度函数 p(x),函数 f(x),其中 x=(x1,x2,,xk)T
输出:p(x) 的随机样本 {x(m+1),x(m+2),,x(n)},函数样本均值 fmn
参数:收敛步数 m, 迭代步数 n
(1)任意选择一个初始值 x0
(2)对 i=1,2,,n 循环执行
  设在第 (i1) 次迭代结束时分量 xj 的取值为 xj(i1)
  (a)对 j=1,2,,k 循环执行
    (i)在第 i 次迭代的第 j 步,由建议分布 q(xj(i1),xj|xj(i)) 抽样产生分量 xj 的候选值 xj(i)
        这里 xj(i) 表示在第 i 次迭代的第 (j1) 步后的 x(i) 除去 xj(i1) 的所有值,即

xj(i)=(x1(i),,xj1(i),xj+1(i1),,xk(i1))T

    (ii)计算接受概率

α(xj(i1),xj(i)|xj(i))=min{1,p(xj(i)|xj(i))q(xj(i),xj(i1)|xj(i))p(xj(i1)|xj(i))q(xj(i1),xj(i)|xj(i))}

    (iii)从区间 (0,1) 中按均匀分布随机抽取一个数 u
        若 uα(xj(i1),xj(i)|xj(i)),则状态 xj(i)=xj(i);否则,状态 xj(i)=xj(i1)
(3)得到样本集合 {x(m+1),x(m+2),,x(n)}
计算

fmn=1nmi=m+1nf(x(i))

习题19.7

  假设进行伯努利实验,后验概率为 P(θ|y),其中变量 y{0,1} 表示实验可能的结果,变量 θ 表示结果为 1 的概率。再假设先验概率 P(θ) 遵循 Beta 分布 B(α,β),其中 α=1,β=1;似然函数 P(y|θ) 遵循二项分布$ \text{Bin}(n, k, \theta)$,其中 n=10,k=4,即实验进行 10 次其中结果为 1 的次数为 4。试用 Metropolis-Hastings 算法求后验概率分布 P(θ|y)P(θ)P(y|θ) 的均值和方差。(提示:可采用 Metropolis 选择,即假设建议分布是对称的。)

解答:

解题思路

  1. 给出 Metropolis-Hastings 算法
  2. 写出目标分布和建议分布
  3. 自编程实现 Metropolis-Hastings 算法求解

解答步骤

第1步:Metropolis-Hastings 算法

  Metropolis-Hastings 算法的步骤详见书中第373~374页算法19.2。

第2步:写出目标分布和建议分布

  根据题意,可知后验概率 P(θ)B(1,1),后验函数 P(y|θ)Bin(10,4,θ)

  则后验概率分布

P(θ|y)P(θ)P(y|θ)B(1,1)Bin(10,4,θ)

  可取建议分布为 B(1,1),接受分布为 Bin(10,4,θ)

第3步:自编程实现 Metropolis-Hastings 算法求解

python
import matplotlib.pyplot as plt
import numpy as np
from scipy.stats import beta, binom


class MetropolisHastings:
    def __init__(self, proposal_dist, accepted_dist, m=1e4, n=1e5):
        """
        Metropolis Hastings

        :param proposal_dist: 建议分布
        :param accepted_dist: 接受分布
        :param m: 收敛步数
        :param n: 迭代步数
        """
        self.proposal_dist = proposal_dist
        self.accepted_dist = accepted_dist
        self.m = m
        self.n = n

    @staticmethod
    def __calc_acceptance_ratio(q, p, x, x_prime):
        """
        计算接受概率

        :param q: 建议分布
        :param p: 接受分布
        :param x: 上一状态
        :param x_prime: 候选状态
        """
        prob_1 = p.prob(x_prime) * q.joint_prob(x_prime, x)
        prob_2 = p.prob(x) * q.joint_prob(x, x_prime)
        alpha = np.min((1., prob_1 / prob_2))
        return alpha

    def solve(self):
        """
        Metropolis Hastings 算法求解
        """
        all_samples = np.zeros(self.n)
        # (1) 任意选择一个初始值
        x_0 = np.random.random()
        for i in range(int(self.n)):
            x = x_0 if i == 0 else all_samples[i - 1]
            # (2.a) 从建议分布中抽样选取
            x_prime = self.proposal_dist.sample()
            # (2.b) 计算接受概率
            alpha = self.__calc_acceptance_ratio(self.proposal_dist, self.accepted_dist, x, x_prime)
            # (2.c) 从区间 (0,1) 中按均匀分布随机抽取一个数 u
            u = np.random.uniform(0, 1)
            # 根据 u <= alpha,选择 x 或 x_prime 进行赋值
            if u <= alpha:
                all_samples[i] = x_prime
            else:
                all_samples[i] = x

        # (3) 随机样本集合
        samples = all_samples[self.m:]
        # 函数样本均值
        dist_mean = samples.mean()
        # 函数样本方差
        dist_var = samples.var()
        return samples[self.m:], dist_mean, dist_var

    @staticmethod
    def visualize(samples, bins=50):
        """
        可视化展示
        :param samples: 抽取的随机样本集合
        :param bins: 频率直方图的分组个数
        """
        fig, ax = plt.subplots()
        ax.set_title('Metropolis Hastings')
        ax.hist(samples, bins, alpha=0.7, label='Samples Distribution')
        ax.set_xlim(0, 1)
        ax.legend()
        plt.show()
python
class ProposalDistribution:
    """
    建议分布
    """

    @staticmethod
    def sample():
        """
        从建议分布中抽取一个样本
        """
        # B(1,1)
        return beta.rvs(1, 1, size=1)

    @staticmethod
    def prob(x):
        """
        P(X = x) 的概率
        """
        return beta.pdf(x, 1, 1)

    def joint_prob(self, x_1, x_2):
        """
        P(X = x_1, Y = x_2) 的联合概率
        """
        return self.prob(x_1) * self.prob(x_2)
python
class AcceptedDistribution:
    """
    接受分布
    """

    @staticmethod
    def prob(x):
        """
        P(X = x) 的概率
        """
        # Bin(4, 10)
        return binom.pmf(4, 10, x)
python
import warnings
warnings.filterwarnings("ignore")

# 收敛步数
m = 1000
# 迭代步数
n = 10000

# 建议分布
proposal_dist = ProposalDistribution()
# 接受分布
accepted_dist = AcceptedDistribution()

metropolis_hastings = MetropolisHastings(proposal_dist, accepted_dist, m, n)

# 使用 Metropolis-Hastings 算法进行求解
samples, dist_mean, dist_var = metropolis_hastings.solve()
print("均值:", dist_mean)
print("方差:", dist_var)

# 对结果进行可视化
metropolis_hastings.visualize(samples, bins=20)
均值: 0.4214185307283342
方差: 0.019466091658555083

png

习题19.8

  设某试验可能有五种结果,其出现的概率分别为

θ4+18,θ4,η4,η4+38,12(1θη)

模型含有两个参数 θη,都介于 0 和 1 之间。现有 22 次试验结果的观测值为

y=(y1,y2,y3,y4,y5)=(14,1,1,1,5)

其中 yi 表示 22 次试验中第 i 个结果出现的次数,i=1,2,,5。试用吉布斯抽样估计参数 θη 的均值和方差。

解答

解题思路

  1. 给出吉布斯抽样算法
  2. 定义目标概率的密度函数和各参数的满条件分布
  3. 自编程实现吉布斯抽样算法进行求解

解答步骤

第1步:吉布斯抽样算法

  根据书中第19.5.2节的吉布斯抽样算法的描述:

算法19.3(吉布斯抽样)
输入:目标概率分布的密度函数 p(x),函数 f(x)
输出:p(x) 的随机样本 xm+1,xm+2,,xn,函数样本均值 fmn
参数:收敛步数 m,迭代步数 n
(1)初始化。给出初始样本 x(0)=(x1(0),x2(0),,xk(0))T
(2)对 i 循环执行
设第 (i1) 次迭代结束时的样本为 x(i1)=(x1(i1),x2(i1),,xk(i1))T,则第 i 次迭代进行如下几步操作:

{(1) 由满条件分布 p(x1|x2(i1),,xk(i1)) 抽取 x1(i)(j) 由满条件分布 p(xj|x1(i),,xj1(i),xj+1(i1),,xk(i1)) 抽取 xj(i)(k) 由满条件分布 p(xk|x1(i),,xk1(i)) 抽取 xk(i)

得到第 i 次迭代值 x(i)=(x1(i),x2(i),,xk(i))T
(3)得到样本集合

{x(m+1),x(m+2),,x(n)}

(4)计算

fmn=1nmi=m+1nf(x(i))

第2步:定义目标概率的密度函数和各参数的满条件分布

  根据题意,可知目标概率的分布函数为

P=(p1,p2,p3,p4,p5)=(θ4+18, θ4, η4, η4+38, 12(1θη))

  可得:

θ4+18>0θ4>0η4>0η4+38>012(1θη)>0θ4+18+θ4+η4+η4+38+12(1θη)=10<θ<10<η<1

  求解得到:

θ+η<10<θ<10<η<1

  则参数 θη 的满分布条件概率为

P(θ|y,η)=((θ4+18)14, θ4, η4, η4+38, (12(1θη))5),θ(0,1η)P(η|y,θ)=((θ4+18)14, θ4, η4, η4+38, (12(1θη))5),η(0,1θ)

第2步:编程实现吉布斯抽样算法进行求解

python
import matplotlib.pyplot as plt
import numpy as np


class GibbsSampling:
    def __init__(self, target_dist, j, m=1e4, n=1e5):
        """
        Gibbs Sampling 算法

        :param target_dist: 目标分布
        :param j: 变量维度
        :param m: 收敛步数
        :param n: 迭代步数
        """
        self.target_dist = target_dist
        self.j = j
        self.m = int(m)
        self.n = int(n)

    def solve(self):
        """
        Gibbs Sampling 算法求解
        """
        # (1) 初始化
        all_samples = np.zeros((self.n, self.j))
        # 任意选择一个初始值
        x_0 = np.random.random(self.j)
        # x_0 = np.array([0.5, 0.5])
        # (2) 循环执行
        for i in range(self.n):
            x = x_0 if i == 0 else all_samples[i - 1]
            # 满条件分布抽取
            for k in range(self.j):
                x[k] = self.target_dist.sample(x, k)
            all_samples[i] = x
        # (3) 得到样本集合
        samples = all_samples[self.m:]
        # (4) 计算函数样本均值
        dist_mean = samples.mean(0)
        dist_var = samples.var(0)
        return samples[self.m:], dist_mean, dist_var

    @staticmethod
    def visualize(samples, bins=50):
        """
        可视化展示
        :param samples: 抽取的随机样本集合
        :param bins: 频率直方图的分组个数
        """
        fig, ax = plt.subplots()
        ax.set_title('Gibbs Sampling')
        ax.hist(samples[:, 0], bins, alpha=0.7, label='$\\theta$')
        ax.hist(samples[:, 1], bins, alpha=0.7, label='$\\eta$')
        ax.set_xlim(0, 1)
        ax.legend()
        plt.show()
python
class TargetDistribution:
    """
    目标概率分布
    """

    def __init__(self):
        # 联合概率值过小,可对建议分布进行放缩
        self.c = self.__select_prob_scaler()

    def sample(self, x, k=0):
        """
        使用接受-拒绝方法从满条件分布中抽取新的分量 x_k
        """
        theta, eta = x
        if k == 0:
            while True:
                new_theta = np.random.uniform(0, 1 - eta)
                alpha = np.random.uniform()
                if (alpha * self.c) < self.__prob([new_theta, eta]):
                    return new_theta
        elif k == 1:
            while True:
                new_eta = np.random.uniform(0, 1 - theta)
                alpha = np.random.uniform()
                if (alpha * self.c) < self.__prob([theta, new_eta]):
                    return new_eta

    def __select_prob_scaler(self):
        """
        选择合适的建议分布放缩尺度
        """
        prob_list = []
        step = 1e-3
        for theta in np.arange(step, 1, step):
            for eta in np.arange(step, 1 - theta + step, step):
                prob = self.__prob((theta, eta))
                prob_list.append(prob)
        searched_max_prob = max(prob_list)
        upper_bound_prob = searched_max_prob * 10
        return upper_bound_prob

    @staticmethod
    def __prob(x):
        """
        P(X = x) 的概率
        """
        theta = x[0]
        eta = x[1]
        p1 = (theta / 4 + 1 / 8) ** 14
        p2 = theta / 4
        p3 = eta / 4
        p4 = (eta / 4 + 3 / 8)
        p5 = 1 / 2 * (1 - theta - eta) ** 5
        p = (p1 * p2 * p3 * p4 * p5)
        return p
python
# 收敛步数
m = 1e3
# 迭代步数
n = 1e4

# 目标分布
target_dist = TargetDistribution()

# 使用 Gibbs Sampling 算法进行求解
gibbs_sampling = GibbsSampling(target_dist, 2, m, n)

samples, dist_mean, dist_var = gibbs_sampling.solve()

print(f'theta均值:{dist_mean[0]}, theta方差:{dist_var[0]}')
print(f'eta均值:{dist_mean[1]}, eta方差:{dist_var[1]}')

# 对结果进行可视化
GibbsSampling.visualize(samples, bins=20)
theta均值:0.5200493163002229, theta方差:0.018093366768230302
eta均值:0.12315468306475189, eta方差:0.006544978550617504

png