MCMC简介

一、重温贝叶斯公式

首先我们先复习一下贝叶斯公式:

P ( θ ∣ x ) = P ( x ∣ θ ) P ( θ ) P ( x ) P(\theta|x) = \frac{P(x|\theta) P(\theta)}{P(x)} P(θx)=P(x)P(xθ)P(θ)

其中各项的说明如下:
P ( θ ∣ x ) P(\theta|x) P(θx):后验概率,给定观测数据 x x x后,我们模型的参数 θ \theta θ的概率,该项是我们最终想要获取的解;
P ( θ ) P(\theta) P(θ) :先验概率,在没有看到任何数据之前,我们对于模型参数 θ \theta θ的猜想;
P ( x ∣ θ ) P(x|\theta) P(xθ):似然,我们对数据分布的猜想;
P ( x ) P(x) P(x):证据,也称为边缘似然,是我们遍历所有可能的 θ \theta θ值后,得到的 x x x观测值的概率的平均;

显然,对于大部分模型来说, P ( x ) P(x) P(x)是无法计算的,这也是贝叶斯公式在实际应用中存在的核心难点,即我们无法直接通过公式计算得到结果。
面对这种问题,一个很直观的想法是,那我们能否通过蒙特卡洛采样的方法来进行近似呢?很遗憾,直接对后验分布进行采样不仅同样需要通过贝叶斯公式来运算,而且还增加了一些逆向运算。
这个时候就只能搬出我们的救兵MCMC了。

二、MCMC的基本概念

MCMC的中文全称是马尔可夫链蒙特卡洛采样(Markov chain Monte Carlo),意为建立一个马尔可夫链来进行蒙特卡洛模拟 (constructing a Markov chain to do Monte Carlo approximation)。
其具体的做法是,构建一个可逆的马尔可夫链,并使得该链的状态转化概率与后验分布的概率分布一致。这样,在这个链上不断移动,我们就获得了想要的后验分布的随机样本。可逆的严格定义是:马尔可夫链必须满足细致平衡条件,即从状态 i i i跳转到状态 j j j的概率必须与从状态 j j j跳转到状态 i i i的概率相等。

以Metropolis-Hasting算法为例,简单介绍MCMC的工作流程:

  1. 给参数 x i x_i xi赋予一个初始值(随机数或经验值)。
  2. 从某个简单对称的分布 Q ( x i + 1 ∣ x i ) Q(x_{i+1}|x_i) Q(xi+1xi)中选一个新的值 x i + 1 x_{i+1} xi+1 Q Q Q通常使用高斯分布或均匀分布。注:该步骤可理解为对状态 x i x_i xi施加一个随机扰动。
  3. 根据Metropolis-Hasting准则计算接受 x i + 1 x_{i+1} xi+1的概率: p α ( x i + 1 ∣ x i ) = m i n ( 1 , p ( x i + 1 ) p ( x i ) ) p_{\alpha}(x_{i+1}|x_i) = min\Big(1, \frac{p(x_{i+1})}{p(x_i)}\Big) pα(xi+1xi)=min(1,p(xi)p(xi+1))
  4. 从位于区间 [ 0 , 1 ] [0,1] [0,1]内的均匀分布中随机取一个值,如果上一步骤中得到概率值大于该值,则接受新样本,否则仍保持原值。
  5. 回到第2步重新迭代,直到我们有足够多的样本。

由上述流程可知,当 p ( x i + 1 ) > p ( x i ) p(x_{i+1})>p(x_i) p(xi+1)>p(xi)时,算法一定会接受该样本,否则将以 p ( x i + 1 ) p ( x i ) \frac{p(x_{i+1})}{p(x_i)} p(xi)p(xi+1)的概率接受该样本。显然, p ( x ) p(x) p(x)的计算是该算法的核心步骤,那对于一个实际的问题, p ( x ) p(x) p(x)要如何计算呢?

三、代码实现(Metropolis-Hasting 算法)

3.1 MCMC拟合数据分布

使用MCMC算法生成样本数据来拟合 B e t a ( 0.5 , 2 ) Beta(0.5, 2) Beta(0.5,2)分布:
在这里插入图片描述

from scipy import stats
import numpy as np
import matplotlib.pyplot as plt
import seaborn as sns
palette = 'muted'
sns.set_palette(palette)
sns.set_color_codes(palette)


def metropolis1(func, steps=10000):
    samples = np.zeros(steps)
    old_x = func.mean()
    old_prob = func.pdf(old_x)

    for i in range(steps):
        new_x = old_x + np.random.normal(0, 0.5)
        new_prob = func.pdf(new_x)
        acceptance = new_prob/old_prob
        if acceptance >= np.random.random():
            samples[i] = new_x
            old_x = new_x
            old_prob = new_prob
        else:
            samples[i] = old_x
    return samples


np.random.seed(345)
func = stats.beta(0.5, 2)
samples = metropolis1(func=func)
x = np.linspace(0.01, .99, 100)
y = func.pdf(x)
plt.xlim(0, 1)
plt.plot(x, y, 'r-', lw=3, label='True distribution')
plt.hist(samples, bins=30, density=True, label='Estimated distribution')
plt.xlabel('$x$', fontsize=14)
plt.ylabel('$pdf(x)$', fontsize=14)
plt.legend(fontsize=14)
plt.show()

3.2 MCMC获取样本参数

假设x服从以下正态分布
μ ∼ N o r m a l ( 0 , 1 ) μ∼Normal(0,1) μNormal(0,1) x ∣ μ ∼ N o r m a l ( x ; μ , 1 ) x|μ∼Normal(x;μ,1) xμNormal(x;μ,1)

import numpy as np
from scipy.stats import norm


def sampler(data, samples=4, mu_init=.5, proposal_width=.5, mu_prior_mu=0, mu_prior_sd=1.):
    mu_current = mu_init
    posterior = [mu_current]
    for i in range(samples):
        # suggest new position
        mu_proposal = norm(mu_current, proposal_width).rvs()
        # Compute likelihood by multiplying probabilities of each data point
        likelihood_current = norm(mu_current, 1).pdf(data).prod()
        likelihood_proposal = norm(mu_proposal, 1).pdf(data).prod()
        # Compute prior probability of current and proposed mu
        prior_current = norm(mu_prior_mu, mu_prior_sd).pdf(mu_current)
        prior_proposal = norm(mu_prior_mu, mu_prior_sd).pdf(mu_proposal)
        p_current = likelihood_current * prior_current
        p_proposal = likelihood_proposal * prior_proposal
        # Accept proposal?
        p_accept = p_proposal / p_current
        # Usually would include prior probability, which we neglect here for simplicity
        accept = np.random.rand() < p_accept
        if accept:
            # Update position
            mu_current = mu_proposal
        posterior.append(mu_current)
    return np.array(posterior)

四、为什么MCMC是有效的?

让我们往回看一步,需要注意接受概率是整个事情有效的关键,通过先验与似然的乘积计算出的跳转概率与根据后验计算得到跳转概率是完全一致的:

P ( μ ∣ x ) P ( μ 0 ∣ x ) = P ( x ∣ μ ) P ( μ ) P ( x ) P ( x ∣ μ 0 ) P ( μ 0 ) P ( x ) = P ( x ∣ μ ) P ( μ ) P ( x ∣ μ 0 ) P ( μ 0 ) \frac{P(\mu|x)}{P(\mu_0|x)}=\frac{\frac{P(x|\mu) P(\mu)}{P(x)}}{\frac{P(x|\mu_0) P(\mu_0)}{P(x)}} = \frac{P(x|\mu) P(\mu)}{P(x|\mu_0) P(\mu_0)} P(μ0x)P(μx)=P(x)P(xμ0)P(μ0)P(x)P(xμ)P(μ)=P(xμ0)P(μ0)P(xμ)P(μ)

可以看到,我们无法计算的边缘项 P ( x ) P(x) P(x)被约掉了,我们获得的跳转概率等同于通过后验计算得到,所以我们的参数会更多的在高概率密度的区域停留,而不是低概率密度的区域。

  • 8
    点赞
  • 52
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值