首页 > 编程语言 >Python贝叶斯MCMC:Metropolis-Hastings、Gibbs抽样、分层模型、收敛性评估

Python贝叶斯MCMC:Metropolis-Hastings、Gibbs抽样、分层模型、收敛性评估

时间:2023-10-24 23:47:19浏览次数:36  
标签:Metropolis 后验 Python ...... prior 分布 np MCMC

 

全文链接:https://tecdat.cn/?p=33961

原文出处:拓端数据部落公众号

在常规的马尔可夫链模型中,我们通常感兴趣的是找到一个平衡分布。

MCMC则是反过来思考——我们将平衡分布固定为后验分布:

image.png

并寻找一种转移核,使其收敛到该平衡分布。

岛屿示例

首先提供一个示例,以具体展示Metropolis算法的机制,然后探讨为什么它有效。

以一个有趣的例子开始,讲述了政治家访问一系列岛屿以争取支持的情况——由于缺乏经验,政治家使用简单的规则来确定下一个要访问的岛屿。每天,政治家选择一个相邻的岛屿,并将其人口与当前岛屿的人口进行比较。如果相邻的岛屿人口更多,则政治家前往该岛屿。如果相邻的岛屿人口更少,则政治家以概率 p=pneighbor/pcurrent=neighbor/current 访问该岛屿;否则,政治家就留在同一个岛上。经过多天的访问后,政治家最终会在每个岛上花费的时间与每个岛的人口成比例——换句话说,正确地估计了每个岛的人口分布。

   
    pos = start  # 起始位置
   ......
    for i in range(niter):
        # 从建议分布中生成样本
         ......

        next_pos = pos + k
        # 在建议位置处计算未归一化的目标分布值
        next_pop = islands[next_pos]
        # 计算接受概率
        p = min(1, next_pop/pop)
        # 使用均匀分布的随机数决定接受/拒绝建议
         ......

真实人口比例

   
......

sns.barplot(x=np.arange(len(data)), y=data)
pass

image.png

估计人口比例

   
......

sns.barplot(x=np.arange(len(data)), y=data)
pass

image.png

通用 Metropolis 算法

   
pythonCopy Code
def metroplis(start, target, proposal, niter, nburn=0):
 ......

        if np.random.random() < p:
            current = proposed
        post.append(current)
    return post[nburn:]

应用于岛屿跳跃问题

   
pythonCopy Code
target = lambda x: islands[x]
......

sns.barplot(x=np.arange(len(data)), y=data)
pass

../_images/notebooks_S10D_MCMC_17_0.png

贝叶斯数据分析

贝叶斯数据分析的基本目标是确定后验分布

image.png

其中分母为

image.png

在这里,

  • p(X | θ) 是似然函数,
  • p(θ) 是先验分布,
  • p(X) 是归一化常数,也称为证据或边缘似然

动机示例

我们将使用一个示例来估计一枚硬币的偏倚,给定一个由n次投掷组成的样本,以说明一些方法。

分析解决方案

如果我们将贝塔分布作为先验分布,那么后验分布有一个闭合形式的解。

  python
......

ci = post.interval(0.95)

thetas = np.linspace(0, 1, 200)
......

plt.legend(loc='upper left')
pass

../_images/notebooks_S10D_MCMC_22_0.png

数值积分

数值积分的一种简单方法是在一组θ值的网格上估计值。为了计算后验分布,我们找到每个θ值的先验和似然函数,并且对于边际似然,我们用等价的求和替换积分。

image.png

这样做的一个优点是先验分布不必是共轭的(尽管下面的示例为了方便比较使用了相同的贝塔先验),因此在选择适当的先验分布时没有限制。

  python
thetas = np.linspace(0, 1, 200)
......

plt.xlim([0, 1])
plt.xlabel(r'$\theta$', fontsize=14)
plt.ylabel('Density', fontsize=16)
plt.legend()
pass

../_images/notebooks_S10D_MCMC_24_0.png

马尔可夫链蒙特卡洛(MCMC)

本文只涵盖了MCMC的基本思想和三种常见变体- Metroplis,Metropolis-Hastings和Gibbs采样。所有代码都将从头开始构建,以说明拟合MCMC模型所涉及的内容,但只展示了玩具示例,因为目标是概念理解。

在贝叶斯统计中,我们希望估计后验分布,但由于分母中的高维积分(边际似然)通常难以处理。我们在蒙特卡洛积分中遇到的其他一些思想在这里也是相关的,例如独立样本的蒙特卡洛积分和提议分布的使用(例如拒绝采样和重要性采样)。正如我们从蒙特卡洛积分中看到的那样,如果我们可以以某种方式抽取许多来自后验分布的样本,我们就可以近似表示后验p(θ|X)。对于普通蒙特卡洛积分,我们需要样本是来自后验分布的独立抽取,如果我们实际上不知道后验分布是什么(因为我们无法计算边际似然),这就是一个问题。

MCMC有几种变体,但最容易理解的是Metropolis-Hastings随机游走算法,我们将从这里开始。

用于估计硬币偏倚的Metropolis-Hastings随机游走算法

要执行Metropolis-Hastings算法,我们需要从以下分布中随机抽取样本:

  • 标准均匀分布
  • 我们选择为N(0,σ)的提议分布p(x)
  • 与后验概率成比例的目标分布g(x)

给定对于θ的初始猜测,具有正概率被抽取,Metropolis-Hastings算法按如下方式进行:

  • 选择一个新的建议值(θp),使得θp=θ+Δθ,其中Δθ∼N(0,σ)
  • 计算比值

image.png

其中g是后验概率。

  • 如果提议分布不对称,我们需要加权接受概率以保持稳定分布的细节平衡(可逆性),并计算

image.png

由于我们正在取比值,分母会取消任何与g成比例的分布 - 因此我们可以使用

image.png

  • 如果ρ≥1,则设置θ=θp
  • 如果ρ<1,则以概率ρ将θ=θp,否则设置θ=θ(这是我们使用标准均匀分布的地方)
  • 重复前面的步骤

经过一定数量的迭代,样本 θk+1, θk+2, ... 将是从后验分布中抽取的样本。

Metropolis-Hastings可以使用不同的提议分布:

  • 独立采样器使用与当前值θ无关的提议分布。在这种情况下,为了效率,提议分布需要与后验分布相似,同时确保接受比率在后验的尾部区域有界。
  • 随机游走采样器(在此示例中使用)在当前值θ为中心处进行随机步骤 - 效率在小步长和高接受概率之间进行权衡,以及大步长和低接受概率之间进行权衡。请注意(课堂上将绘制图示),随机游走可能需要很长时间才能遍历概率分布的狭窄区域。通过更改步长(例如,对于多变量正态提议分布,缩放ΣΣ)以使目标比例的建议被接受,称为“调整”。
  • 目前正在进行关于不同提议分布以有效采样后验分布的研究。

我们首先看一个数值示例,然后尝试理解其原理为什么有效。

   
def target(lik, prior, n, h, theta):
......

lik = stats.binom
prior = stats.beta(a, b)
......

for i in range(niters):
  ......

print("Efficiency = ", naccept/niters)

image.png

   

post = stats.beta(h+a, n-h+b)
......

plt.legend(loc='upper left')
pass

../_images/notebooks_S10D_MCMC_28_0.png

评估收敛性

迹线图通常用于非正式地评估随机收敛。严格证明收敛是一个未解决的问题,但是在实践中经常采用运行多个链并检查它们是否收敛到类似分布的简单想法。

  python
def mhin(niters, n, h, theta, lik, prior, sigma):
   ......

        if u < rho:
            theta = theta_p
        samples.append(theta)
    return samples


n = 100
......
) for theta in np.arange(0.1, 1, 0.2)]

# 多链收敛性

for samples in sampless:
   ......

plt.ylim([0, 1]);

notebooks_S10D_MCMC_32_0.png

为什么 Metropolis-Hastings 算法有效?

有两个主要的想法——首先,MCMC 生成的样本构成了一个马尔科夫链,并且这个马尔科夫链具有唯一的稳态分布,如果我们生成了非常多的样本,它总是会达到这个稳态分布。第二个想法是证明这个稳态分布正是我们所寻找的后验分布。这里只给出直观的理解。

一:存在唯一的稳态

由于可能的转换只依赖于当前和建议的 θ 值,Metropolis-Hastings 样本中 θ 的连续值构成了一条马尔科夫链。请记住,对于具有转移矩阵 T 的马尔科夫链,

image.png

意味着π是一个稳态分布。如果可以从任何状态转换到任何其他状态,则矩阵是不可约的。如果此外,不可能陷入振荡,则矩阵也是周期性或混合的。对于有限状态空间,不可约性和非周期性保证了唯一稳态。对于连续状态空间,我们需要正反馈的另一个属性——从任何状态开始,回到原始状态的预期时间必须是有限的。如果我们具有不可约性、非周期性和正反馈的所有 3 个属性,则存在唯一的稳态分布。术语遍历有点令人困惑——大多数标准定义将遍历性视为等同于不可约性,但是经常在贝叶斯文本中,遍历性意味着不可约性、非周期性和正反馈,我们将遵循后一种惯例。对于另一种直观的视角,随机游走 Metropolis-Hasting 算法类似于扩散过程。由于所有状态都是相互通信的(通过设计),最终系统将进入平衡状态。这类似于收敛到稳态。

示例

我们将使用熟悉的示例来估计两个硬币的偏差,给定样本对 (z1,n1)(θ1,η1) 和 (z2,n2)(θ2,η2),其中 zi 是硬币 i 中 n_i 次投掷中头的个数。

   
def b:
  ......

    return np.clip(theta**z * (1-theta)**(N-z), 0, 1)

def bern......

    return bern(theta1, z1, N1) * bern(theta2, z2, N2)

def maketas(xmin, xmax, n):
  ......

    return thetas
   
from m......
t_kw=dict(projection=projection, aspect='equal'), figsize=(12,3))
    if projection == '3d':
     ......

        ax[0].contour(X, Y, prior, cmap=plt.cm.jet)
        ax[1].contour(X, Y, likelihood, cmap=plt.cm.jet)
    ......

    plt.tight_layout()

the......
etas(0, 1, 101)
X, Y = np.meshgrid(thetas1, thetas2)

分析方法

   
......

prior = stats.beta(a, b).pdf(X) * stats.beta(a, b).pdf(Y)
l......
)
make_plots(X, Y, prior, likelihood, posterior, projection='3d')

../_images/notebooks_S10D_MCMC_43_0.png

../_images/notebooks_S10D_MCMC_43_1.png

网格近似

   
def ......
as1[1] - thetas1[0]
    width2 = thetas2[1] - thetas2[0]
   ......

    return pmf

_prior = bern2(X, Y,......
10, 10)
prior_grid = c2d(thetas1, thetas2, _prior)
_like......
lihood, posterior_grid)
make_plots(X, Y, prior......
jection='3d')

../_images/notebooks_S10D_MCMC_46_0.png

../_images/notebooks_S10D_MCMC_46_1.png

Metropolis

   
a = 2
b = 3
......

prior = lambda theta1, theta2: stats.beta(a, b).pdf(theta1) * stats.beta(a, b).pdf(theta2)
lik = partial(......
(theta1, theta2)

theta = np.array([0.5, 0.5])
......


thetas = np.zeros((ni......
float)
for i in range(niters):
  ......

    if i >= burnin:
        thetas[i-burnin] = theta

kde = stats.gaussian_kde(thetas.T)
......

make_plots(X, Y, prior(X, Y), lik......
metroplis, projection='3d')

../_images/notebooks_S10D_MCMC_49_0.png

../_images/notebooks_S10D_MCMC_49_1.png

Gibbs

   
a = 2
......

N2 = 14

prior = lambda theta1,......
, N2=N2)
target = lambda theta1, theta2: prior(theta1, theta2) * lik(theta1, theta2)

theta = np.ar......
)

thetas = np.zeros((niters-burnin,2), np.float)
for i in r......
N2 - z2).rvs()]

    if i >= burnin:
        thetas[i-burnin] = theta

kde = stats.gaussian_kde(thetas.T)
X......
gibbs, projection='3d')

../_images/notebooks_S10D_MCMC_52_0.png

../_images/notebooks_S10D_MCMC_52_1.png

分层模型

分层模型具有以下结构 - 首先,我们指定数据来自具有参数 θ 的分布

image.png

而参数本身来自具有超参数 λ 的另一个分布

image.png

最后,λ 来自先验分布

image.png

可以有更多层次的分层模型 - 例如,可以为 λ 的分布指定超级超参数,依此类推。

请注意,由于分层模型具有条件独立的结构,Gibbs采样通常是MCMC采样策略的自然选择。

   
from numpy.random import gamma as rgamma # 重命名,以便我们可以将 gamma 用作参数名称。
   
def lambda_updat......


def gibbs(niter,......
a_, y)
        lambda_ = lambda_update(alpha, beta_, y, t)

        betas_[i] = beta_
        lambdas_[i,:] = lambda_

    return betas_, lambdas_
   
......

beta0 = 1
y = np.arr......
 np.float)
niter = 1000
   
betas, lambdas = gibbs(nit......

print('%.3f' % betas.std(ddof=1))
print(lambdas.mean(axis=0))
print(lambdas.std(ddof=1, axis=0))

image.png

   
for i in range(len(lambdas.T)):
 ......

    plt.title('Trace for $\lambda$%d' % i)
plt.tight_layout()

../_images/notebooks_S10D_MCMC_61_0.png


BB-Being-objective-about-budgets-1159610159-STANDARD-1536x1536.jpg

最受欢迎的见解

1.用R语言模拟混合制排队随机服务排队系统

2.R语言中使用排队论预测等待时间

3.R语言中实现马尔可夫链蒙特卡罗MCMC模型

4.R语言中的马尔科夫机制转换(Markov regime switching)模型

5.python中使用马尔可夫决策过程(MDP)动态编程来解决最短路径强化学习问题

6.用R语言模拟混合制排队随机服务排队系统

7.Python基于粒子群优化的投资组合优化

8.R语言几何布朗运动 GBM模拟股票价格优化建立期权定价概率加权收益曲线可视化

9.R语言进行支持向量机回归SVR和网格搜索超参数优化

 

标签:Metropolis,后验,Python,......,prior,分布,np,MCMC
From: https://www.cnblogs.com/tecdat/p/17786031.html

相关文章

  • 使用BBP算法计算π,Python实现
     BBP算法(Bailey-Borwein-Plouffe算法)是一种用于计算π的算法,它可以直接计算出π的十六进制表示的任意一位。BBP算法由SimonPlouffe于1995年提出,基于DavidBailey和PeterBorwein在1995年的工作。BBP算法的基本思想是使用级数展开,将π表示为一个无限级数的和。具体来说,BBP算法......
  • 用Python发一个优雅的朋友圈,1行代码搞定
    大家好,这里是程序员晚枫,这段时间给大家分享多个微信自动化的代码:今天再给大家分享一个:用Python发一个好看的朋友圈的代码。效果展示最近很多P图软件实现了一个效果:把一张图片分成9张,如下图所示。......
  • python进阶知识体系笔记,整理近200页,共14大体系 第(1)期
    本文从14大模块展示了python高级用的应用。分别有Linux命令,多任务编程、网络编程、Http协议和静态Web编程、html+css、JavaScript、jQuery、MySql数据库的各种用法、python的闭包和装饰器、mini-web框架、正则表达式等相关文章的详细讲述。完整版笔记直接地址:请移步这里共14......
  • Python 利用pandas 和 matplotlib绘制柱状图
    当你需要展示数据时,图表是一个非常有用的工具。Python中的pandas和matplotlib库提供了丰富的功能,可以帮助你轻松地绘制各种类型的图表。本文将介绍如何使用这两个库,绘制一个店铺销售数量的柱状图,并添加各种元素,如数据标签、图例、网格线等。准备工作在开始之前,你需要安装p......
  • 使用Python随机查询数据库中10个信息然后删除这10个信息
    大家好,我是皮皮。一、前言前几天在Python最强王者交流群【刘苏秦】问了一个Python数据库数据处理的问题,一起来看看吧。cursor=connect.cursor()sql="SELECT*FROMinfoswherestatus=''"cursor.execute(sql)result=random.sample(cursor.fetchall(),10)result=[d......
  • # yyds干货盘点 #使用Python随机查询数据库中10个信息然后删除这10个信息
    大家好,我是皮皮。一、前言前几天在Python最强王者交流群【刘苏秦】问了一个Python数据库数据处理的问题,一起来看看吧。cursor=connect.cursor()sql="SELECT*FROMinfoswherestatus=''"cursor.execute(sql)result=random.sample(cursor.fetchall(),10)result=[dict(i......
  • 代码随想训练营第十四天(Python)| 层序遍历 10 、● 226.翻转二叉树 、101.对称二叉树 2
    层序遍历1、迭代法,使用队列classSolution:deflevelOrder(self,root:Optional[TreeNode])->List[List[int]]:res=[]ifrootisNone:returnresqueue=[root]whilequeue:n=len(queue)......
  • python all()详解
    python内置函数all可用于判断传入的可迭代参数iterable中的所有元素是否都为True,如果是则返回True,反之返回False。如果可迭代对象是空的,也会返回True。在判断元素是否为True时,只要元素不是0、空、None、False,就视为True。all()函数接受一个可迭代对象作为参数,仅当可迭代对象......
  • Python41days
    创建表的完整语法约束条件(在数据类型的基础上在进行约束)unsigned   zerofill    defaultnotnull    unique    primarykey     auto_increment其余SQL语句其他查询关键字select  from  where   orderby   limit  ......
  • python内存监测工具memory_profiler
    内存监测工具memory_profiler目录内存监测工具memory_profiler安装参数注解简单使用输出在日志中mprof使用参考资料memory_profiler是Python的一个第三方库,其功能时基于函数的逐行代码分析工具memory_profiler是一个监控进程内存消耗的模块,也可以逐行分析Python程序的内存......