从马尔科夫过程到吉布斯采样(附程序示例)

article/2025/9/19 11:49:00

目标:如何采取满足某个概率分布的一组数据,比如如何给出满足标准正太分布的1000个点,当然该分布比较简单,生成满足此分布的1000个点并不难,对matlab,python 等都是一行语句的事,但是如果是一个不常见的分布,怎样采集呢?

本文试图通过示例让读者理解从马尔科夫链到Gibbs采样的各种采样方法的不断改进过程。

  • Part 1       马尔科夫过程

马尔科夫假设: 当前状态发生的概率只跟直接相连的前面状态有关。

马尔科夫链示例如下:


某地区天气状态的转移概率矩阵P
 舒适
0.70.250.05
舒适0.650.20.15
0.050.850.1

   假设将某地区天气状况分为热,冷,舒适,三种状态。转移概率矩阵P如上表所示。假设第一天的天气为热,问第100天的天气是怎样的?

根据所学的概率知识可知:

第二天:S2=[ 0.7   0.25   0.05 ]  即第二天70%可能继续热, 25%可能舒适, 很小可能冷。为表示

第三天: S3=S2*P=[0.655  0.2675 0.0775]

第四天:S4=S3*P=[0.63625  0.283125 0.080625]

。。。。。。。。。。。。。。。。。。。。。。。此处省略很多天

第98天: S98=S97*P=[0.632      0.28533333    0.08266667]

第99天: S99=S98*P=[0.632      0.28533333    0.08266667]

第100天: S100=S99*P=[0.632      0.28533333    0.08266667]

先不着急下结论,看如下问题:

问题2:  假设第一天天气为冷,问第100天的天气情况

解决方法同上,S2=[0.05 0.85 0.1], S100=S2*P^99,经计算得

S100=[0.632      0.28533333    0.08266667]

问题3: 假设第一天天气为舒适,问第100天的天气情况

解决方法同上,S2=[0.65 0.2 0.15], S100=S2*P^99,经计算得

S100=[0.632      0.28533333    0.08266667]。

现在从另一个角度审视状态转移矩阵P

P=[[0.7 , 0.25, 0.05],     
      [0.65, 0.2 , 0.15],
      [0.05, 0.85, 0.1 ] ]

P^2=[[0.655 , 0.2675, 0.0775],
        [0.5925, 0.33  , 0.0775],
        [0.5925, 0.2675, 0.14  ]]

P^3=[[0.63625 , 0.283125, 0.080625],
        [0.633125, 0.28    , 0.086875],
        [0.595625, 0.320625, 0.08375 ]]

。。。。。。。。。。。。。。。。。。。。。省略

P^10=[[0.63200006 0.2853333  0.08266664]
          [0.63200002 0.28533325 0.08266673]
          [0.63199944 0.28533387 0.08266668]]

。。。。。。。。。。。。。。。。。。。。。。

P^20=[[0.632      0.28533333 0.08266667]
          [0.632      0.28533333 0.08266667]
          [0.632      0.28533333 0.08266667]]

到此我们发现了一个神奇的现象 ,P若干次幂之后,在乘以P 矩阵也不会发生变化了。

定义:

  • 最后那个不变的状态S 称为平稳分布(Stationary Distribution)有时也被称为均衡分布(Equilibrium Distribution)
  • 细致平稳条件, S*P=S

综上可以得出如下结论:

  • 不管初始状态如何,给定P后,万法归宗,最后的状态是一样的。
  • 存在某一正数M 当N>M后, P^N=P^(>N)
  • S 跟P的关系是 1 vs 多 P  P^2   P^3 ,最后都能归于平稳状态S。
  • 如上条结论,满足细致平稳条件的P 有很多个。

马尔科夫采样: 前提,已知  P 

采样方法:

1 从某个初始分布S0(往往跟稳态分布不一样)出发,采样初始状态x0,

2 根据状态x_t和转移概率矩阵P(已知的)计算条件分布 S(\large x_{t+1}|x_t

3 从分布S采样\large x_{t+1}

4 设置某个阈值,截取后半部分的采样序列。

图1为遵循马尔科夫链的真实数据之间的关系,总体上三者是等价的。但是数据的概率分布是最真实的,也是唯一的,状态转移矩阵并不是唯一的,稳态分布是唯一的。


                                                           

                                                                               图1 马尔科夫链中的数据关系


  •  Part 2       MCMC采样 与 M-H采样

从上一部分我们知道,如果给定一个待采样的分布,也就是平稳分布S,在知道与S 对应的P时,使用马尔科夫采样即可。但是在实际中,我们一般知道问题给出的分布,但是不知道分布对应的转移矩阵。

首先定义细致平稳条件(detailed balance condition) 设平稳分布为S,某转移矩阵为Q

如果S ,Q满足  \large S(i)*Q(i,j)=S(j)*Q(j,i) 则称矩阵Q满足平稳细致条件。上例中的P^10,P^20都满足次条件。

但是如果随意给定一个矩阵,则很难满足。

可以通过改造的方式让给定的Q满足条件,改造方式为\large S(i)*Q(i,j)*{\color{Red} S(j)*Q(j,i)}=S(j)*Q(j,i)*{\color{Red} S(i)*Q(i,j)},红色字体为改造的内容。

定义\large \alpha(i,j)=S(j)*Q(j,i), 可以看出\large \alpha有点类似于后验概率的公式, 我们称之为接受率。

MCMC采样过程如下:

MCMC算法

输入:稳态分布S,转移矩阵Q,初始化状态链\large x_0

方法:

假设t时刻状态为\large x_t, 根据\large x_t, Q采样备选值 a

从均匀分布采样 u~uniform[0 1]

如果u<\large \alpha=S(a)*Q(\large x_t|a) 则接受转移 \large x_{t+1}=a

否则\large x_{t+1}=\large x_t

MCMC采样有个问题,接受率往往很小,导致状态很少转移, 针对这一问题,出现了M-H采样,Metropolis-Hastings

M-H采样过程同MCMC一致,只是转移率取为 min[S(a)/S(x_t),1],可以看出如果a的稳态概率大于当前值的稳态概率,则一定转移,反之,则以一定的概率转移。

总结,MCMC 和M-H 可以理解为经过两次采样,第一次采样的值以一定的概率被接收。

示例;图2 为M-H采样,目标数据的稳态分布为分别为均值是3/30方差为2的正太分布。转移概率为以转移点为均值,方差为1的正太分布。

从图中可以看出,如果初始值离稳态分布的均值差距很大,需要经过较长时间的采样后才能得到符合平稳分布的数据。


                

       图1(a): 均值30, 50000个采样点中前5000个                            图1(c): 均值3, 50000个采样点中前5000个 

                

    图1(b): 均值30, 50000个采样点d的后5000个                              图1(d): 均值3, 50000个采样点中后5000个 

                                                         图2 M-H采样


M-H采样的Python 代码。

import random
import math
from scipy.stats import norm
import matplotlib.pyplot as plt
#% matplotlib inline
pmu=3def norm_dist_prob(theta):y = norm.pdf(theta, loc=pmu, scale=2)return yT = 50000
pi = [0 for i in range(T)]
sigma = 1
t = 0
while t < T-1:t = t + 1pi_star = norm.rvs(loc=pi[t - 1], scale=sigma, size=1, random_state=None)alpha = min(1, (norm_dist_prob(pi_star[0]) / norm_dist_prob(pi[t - 1])))u = random.uniform(0, 1)if u < alpha:pi[t] = pi_star[0]else:pi[t] = pi[t - 1]#plti=pi[T-5000:T-1]
plti=pi[0:4999]
plt.scatter(plti, norm.pdf(plti, loc=pmu, scale=2),color='red')
num_bins = 50
plt.hist(plti, num_bins, normed=1, facecolor='green', alpha=0.7)
plt.show()

 Part 3       Gibbs 采样

M-H采样推广到多维数据的情况。

为啥要Gibbs? 数据的联合概率分布很难确定,尤其是高纬情况下。但边缘概率分布容易得到的情况。

Gibbs 采样过程:

  • 输入平稳分布S(x1,x2),设定状态转移次数阈值n1,需要的样本个数n2
  • 随机初始化初始状态值x1_0和x2_0
  • for t=0:n1+n2_1

          从条件概率分布P(x2|x1(t)中采样得到样本x2(t+1)

          从条件概率分布P(x1|x2(t+1)中采样得到样本x1(t+1)

Gibbs采样过程有点像坐标交替优化法。

示例:摘自注1

                                     


               


 

# -*- coding: utf-8 -*-
"""
Created on Sat Sep 15 11:19:05 2018@author: Administrator
"""from mpl_toolkits.mplot3d import Axes3D
from scipy.stats import multivariate_normal
import matplotlib.pyplot as plt
import random
samplesource = multivariate_normal(mean=[5,-1], cov=[[1,0.5],[0.5,2]])def p_ygivenx(x, m1, m2, s1, s2):return (random.normalvariate(m2 + rho * s2 / s1 * (x - m1), math.sqrt(1 - rho ** 2) * s2))def p_xgiveny(y, m1, m2, s1, s2):return (random.normalvariate(m1 + rho * s1 / s2 * (y - m2), math.sqrt(1 - rho ** 2) * s1))N = 5000
K = 20
x_res = []
y_res = []
z_res = []
m1 = 5
m2 = -1
s1 = 1
s2 = 2rho = 0.5
y = m2for i in xrange(N):for j in xrange(K):x = p_xgiveny(y, m1, m2, s1, s2)y = p_ygivenx(x, m1, m2, s1, s2)z = samplesource.pdf([x,y])x_res.append(x)y_res.append(y)z_res.append(z)num_bins = 50
plt.hist(x_res, num_bins, normed=1, facecolor='green', alpha=0.5)
plt.hist(y_res, num_bins, normed=1, facecolor='red', alpha=0.5)
plt.title('Histogram')
plt.show()fig = plt.figure()
ax = Axes3D(fig, rect=[0, 0, 1, 1], elev=30, azim=20)
ax.scatter(x_res, y_res, z_res,marker='o')
plt.show()

 

注1:(本文相关代码及部分理解来自https://www.cnblogs.com/pinard/p/6638955.html)作者讲的深入浅出,很详细。


http://chatgpt.dhexx.cn/article/k8tmX4xT.shtml

相关文章

sqlloader导出数据指定分隔符_来一份数据库全家桶~

♫. ♪ ~ ♬..♩~ ♫. ♪..♩~ ♫. ♪ ~ ♬..♩..♩~ ♫. ♪ ~ ♬..♩..♩~ ♫. ♪ ~ ♬..♩♫. ♪ ~ ♬..♩~ ♫. ♪..♩~ ♫. ♪ ~ ♬..♩..♩~ ♫. ♪ ~ ♬..♩..♩~ ♫. ♪ ~ ♬..♩ 点击蓝字关注我们♫. ♪ ~ ♬..♩~ ♫. ♪..♩~ ♫. ♪ ~ ♬..♩..♩~ ♫. ♪ ~ ♬..♩..…

使用sqlloader导入数据(千万级)-oracle

前言&#xff1a;笔者业务场景&#xff1a;当前表无分区&#xff0c;需将数据导出&#xff0c;创建分区后&#xff0c;重新导入当前表&#xff1b;当然&#xff0c;该方法同样使用于普通的数据迁移&#xff0c;或新旧表数据同步&#xff08;表结构一致&#xff09; 一、涉及数…

oracle-sqlloader的简单使用

目录 使用场景 简单使用 编写ctl文件 执行命令 使用场景 当你拿到一个txt文件&#xff0c;里面的数据是用统一符号分割的&#xff0c;例如如下文件&#xff0c;就可以考虑使用sqlloader导入到oracle数据库。 简单使用 编写ctl文件 OPTIONS (skip1,rows128) -- sqlldr 命…

使用Sqlloader处理数据

Oracle数据导出工具sqluldr2可以将数据以csv、txt等文件格式导出&#xff0c;适用于大批量数据的导出&#xff0c;导出速度非常快&#xff0c;导出后可以使用Oracle SQL Loader工具将数据导入到数据库中。下面将介绍Sqluldr2和sqlldr在Windows平台下的数据处理过程。 一、获取…

oracle之sqlloader

oracle的sqlloader可以从文件批量的将数据插入到数据库中&#xff0c;避免了使用SQL一句一句插入给数据库带来的压力。在工作中&#xff0c;简单的使用了一下&#xff0c;并没有深入的研究&#xff0c;下面是一个例子。 ① 数据文件信息&#xff1a; tina&#xff0c;12,34…

oracle sqlloader 的简单使用

1、EMP1 建表语句&#xff1a; CREATE TABLE EMP1 (EMPNO NUMBER(8) NOT NULL,ENAME VARCHAR2(10),HIREDATE DATE,JOB VARCHAR2(20),SAL NUMBER(8),DEPTNO NUMBER(8) NOT NULL ); 2、test.txt 数据文件&#xff1a; 1|Abandon1|2022-02-01|销售人员1|2500…

linux sql*loader-704,初见Oracle SqlLoader工具

因为大量的数据存在于文本文件中&#xff0c;需要导入到Oracle&#xff0c;有幸接触到神器SqlLoader. 在安装好Oracle的主机上单独运行sqlldr命令 sqlldr 将看到关于此工具的说明: 也只是简单的一个例子&#xff0c;帮助初次接触的你。 编写一个ctl文件&#xff0c;Oracle数据库…

mysql sql loader_Sql Loader的简单使用

之前总结的关于SQL*Loader的用法&#xff0c;今天又用到&#xff0c;又翻出来看看 SQL*Loader 可将外部文件中的数据加载到Oracle DB的表中。它具有一个功能强大的数据分析引擎&#xff0c;因此对数据文件中数据的格式没有什么限制。 SQL*Loader 使用以下文件&#xff1a;输入数…

Linux中sql*loader-350,SqlLoader

Sqlloader的步骤 1) Oracle 数据库端必须已经建好了需要导入的数据表的结构 2) 存在数据源文件 3) 手工编辑一个XXX.CTL 的控制文件 4) 命令行加载数据 Sqlldr命令具体信息如下图 Sqlldr运行的一个具体例子 sqlldr userid=user1/123456 control=bcp1.ctl log=log/bcp1.log bad=…

如何使用SqlLoader导入数据

Oracle 使用sqlloader导入数据非常方便,下面是我的导入步骤&#xff1a; 第一步&#xff0c;检查机器安装了sqlldr.exe没&#xff1f; 2、建一张表 CREATE TABLE student1 ( sname varchar (20), sage INTEGER, semall varchar (20), sphone VARCHAR (20), saddress varchar (…

MyBatis select标签

在 MyBatis 中&#xff0c;select 标签是最常用也是功能最强大的 SQL 语言&#xff0c;用于执行查询操作。 select 示例语句如下。 SELECT id,NAME,url FROM website WHERE NAME LIKE CONCAT (‘%’,#{name},‘%’) 以上是一个 id 为 selectAllWebsite 的映射语句&#xff0…

MyBatis标签对postgreSQL中returning返回参数的处理

mybatis中用标签处理SQL语句时&#xff0c;遇到pgsql中比较特殊的returning *。 当INSERT时会返回returning后的字段&#xff0c;但是在mybatis中使用INSERT("${sql}")时会遇到如下错误 ps&#xff1a; Mapper method com.lingtu.mapper.EventMapper.insert has an u…

MyBatis 配置文件标签

文章目录 MyBatis 配置文件标签1. properties2. settings3. plugins4. typeAliases5. environments6. mappers MyBatis 配置文件标签 MyBatis 的全局配置文件习惯上命名为&#xff1a;mybatis-config.xml &#xff0c;此文件名仅仅是建议&#xff0c;并非是强制要求。配置文件存…

Mybatis值trim标签

Mybatis具有实现动态SQL的能力&#xff0c;使用这个特性免不了会用到trim这个标签&#xff0c;trim标签的功能简单来说就是自定义格式拼凑SQL语句。 trim有4个属性&#xff1a; prefix&#xff1a;表示在trim包裹的SQL前添加指定内容 suffix&#xff1a;表示在trim包裹…

MyBatis foreach标签

前面我们学习了如何使用 Mybatis if、where、trim 等动态语句来处理一些简单的查询操作。对于一些 SQL 语句中含有 in 条件&#xff0c;需要迭代条件集合来生成的情况&#xff0c;可以使用 foreach 来实现 SQL 条件的迭代。 Mybatis foreach 标签用于循环语句&#xff0c;它很…

mybatis常用标签

一.定义sql语句 1.select 标签 属性介绍: &#xff08;1&#xff09;id :唯一的标识符. &#xff08;2&#xff09;parameterType:传给此语句的参数的全路径名或别名 例:com.test.poso.User或user &#xff08;3&#xff09;resultType :语句返回值类型或别名。注意&#xff…

Mybatis中标签大全

文章目录 一、标签分类 二、标签总结 1. 基础SQL标签 1.1 查询select 1.2 增删改 1.3 其他基础标签 1.3.1 sql 标签 1.3.2 include 标签 1.3.3 if 标签 1.3.4 别名 2. collection与association标签 3. resultMap标签 4. foreach标签 5. where标签 6. set标签 7.…

jarsigner命令行签名打包

jarsigner签名&#xff0c;之前都是通过AS进行签名&#xff0c;通过这种方式也是可以签名的&#xff0c;需要提前把需要的东西准备好&#xff0c;现在把步骤记录在下面。&#xff08;下面的操作都是在jdk的路径下进行操作&#xff09; 1.首先准备Jdk的路径&#xff08;在androi…

jarsigner: 无法打开 jar 文件: tap_unsign.apk

flutter 的 android项目上线&#xff0c;我们在想应用宝发布应用时&#xff0c;需将key.jks文件放入应用宝的空白文件中&#xff0c;在cmd中执行 jarsigner -verbose -keystore key.jks -signedjar baoming.apk tap_unsign.apk name遇到如下报错 jarsigner: 无法打开 jar 文件…

apk重签名之jarsigner命令签名

apk的签名工作可以通过两种方式来完成&#xff1a; 1&#xff09;通过ADT提供的图形化界面完成apk签名&#xff1b;2&#xff09;完全通过DOS命令来完成apk签名 1&#xff09;准备工作 我比较喜欢第2&#xff09;种方式&#xff0c;所以下面将讲解如何通过命令的方式完成apk…