Gibbs sampler

今天将这个所学到的写入到这里以来保留自己学过的痕迹。
Gibbs采样器主要的用途是用来采样的,那么能不能在开始的时候给自己提几个问题呢?
1.为什么要用Gibbs采样,采用Gibbs采样有哪些好处?
2.Gibbs采样是否正确?得到的样本是否为所服从的分布?
3.采样需要注意哪些问题?
1.我们来看,如果现在给定一个高斯分布模型,其中的参数都为已知,那么我们怎么样从这个高斯分布中用计算机来生成一些样本呢?
首先得关注样本的取值范围,即定义域。对于高斯分布模型有:高斯分布的概率密度函数的定义域为(-Inf,Inf),但是,在计算机中,或是现实生活中没有Inf,所以我们就这样做:对于[-3σ,3σ]暂居了很大一部分概率,因此,我们可以将范围扩展到[-9σ,9σ].即高斯分布模型的定义域为:[-3σ,3σ].
2.定义域知道后怎么来采样呢?
    a。将这个定义域分割成很多小格子,然后取格子中间的x值?那么你这样取出来的绝对不会服从高斯模型了。
    b。将定义域分成很多格子,对于每一个格子的x值用中间值代替,然后计算每一个格子的概率,以这个概率(例如,用均匀分布rand函数来产生一个数,当这个数小于这个概率值时我们接受这个x值,当大于这个概率值时,我们拒绝这个x值)来决定什么时候接受和什么时候拒绝。当然非常的接近了,但是,我们对于格子中的值选取的是其中值,这样我们还是不能完美的得到样本数据。当然可以将格子分的很小,以致我们不能够观察出什么不对。这个方法是可行的。
   那么上面这个方法有什么不足吗?首先,我们需要计算每个格子的概率,多大的格子合适呢,x的值该怎么取呢?不可否认,这是一个采样器,但有多的限制。
   c。对于多维概率模型,是不是这样取值很麻烦呢?对我看来,这是很麻烦的事情。


Gibbs采样器:
Gibbs采样器一般运用到高维数据采样的问题中。一维中可以采用MCMC采样器来进行采样。
Gibbs采样器需要知道分布的确定表示形式,即联合分布模型必需确定,但不必知道边缘分布概率。下面就是Gibbs采样器的步骤:
这里先特定到二维p(x,y)
      a.选择一个y0,然后用y0来确定p(x,y0)。这样我们就直接的降掉了一维,此时可以用MCMC或其它方法从p(x,y0)中来产生一个x0.
      b.得到x0后,我们可以用x0来确定p(x0,y),同理可以用p(x0,y)来得到y1.然后再用y1得到x1.
      c.以此不断循环,就能得到二维p(x,y)分布的样本:(x0,y0),(x1,y1),(x2,y2),.... ...
对于多维,其实就是一样的了,对于p(x,y,z,...),如果我们先求x,那么就要先初始化y,z,...;然后用初始化的y,z,...来求x,然后固定x,z,...来求y,等等,这样循环下去。
下面是自己编写的一个Gibbs采样器:
%% Gibbs sampler
%产生样本的分布为一个二维的:p(x,y) = n!/(n-x)!x!*y.^(x+a-1)*(1-y).^(n-x+b-1);
%Gibbs sampler原理是:
%1. 首先从x,y中选点一个,这里选定y,则我们在y的范围内给y选一个值,得到一个y0
%2. 其次将y0代入到p(x,y)中去得到p(x|y=y0)下的一个分布,然后我们从这个分布中产生一个x。
%   当然,这个边缘分布可能交复杂,但是我们可以采用MCMC来进行了,这样得到x0
%3. 将x0代入到p(x,y)中去,得到p(y|x=x0)下的一个分布,我们从这个分布中得到y1。
%4. 然后又由y1产生x1,以此这样循环,自己设定一个循环结束条件:迭代多少次(k)后终止。

len = 20000;
sample = zeros(len,2);
y0 = 0.5 ; %  0< y < 1
k = 1 ;
n = 10 ;
a = 1 ;
b = 2 ;
num = 10 ;
while k <= len
    sample(k,2) = y0 ;
    x0 = 5 ;
    i = 1 ;
    while i <= num 
          pxy0 = factorial(n)/ (factorial(n-x0)*factorial(x0) )* y0.^(x0+a-1)*(1-y0).^(n-x0+b-1);
          x1 = randi([1,10]);
          pxy1 = factorial(n)/ (factorial(n-x1)*factorial(x1) )* y0.^(x1+a-1)*(1-y0).^(n-x1+b-1);
          judge = pxy1/pxy0 ;
          if judge >= 1
              x0 = x1 ;
              i = i + 1 ;
          else
              if rand() < judge
                   x0 = x1 ;
                   i = i + 1 ;
              end
          end
    end
    %得到了x0
    sample(k,1) = x0 ;
    %去获得y1
    i = 1 ;
        while i <= num 
          pyx0 = factorial(n)/ (factorial(n-x0)*factorial(x0) )* y0.^(x0+a-1)*(1-y0).^(n-x0+b-1);
          y1 = rand();
          pyx1 = factorial(n)/ (factorial(n-x0)*factorial(x0) )* y1.^(x0+a-1)*(1-y1).^(n-x0+b-1);
          judge = pyx1/pyx0 ;
          if judge >= 1
              y0 = y1 ;
              i = i + 1 ;
          else
              if rand() < judge
                   y0 = y1 ;
                   i = i + 1 ;
              end
          end
        end
     k = k + 1 ;
end
%% 画图
xx = 1:1:10;
yy = 0:0.01:1;
z = getResult(n,a,b);
mesh(z);
myhist = getHist(sample(100:len,:),xx,yy,1,0.01);
figure;
mesh(myhist);

%%
getResult函数如下:
function z = getResult(n,a,b)
%% 得到一个二维矩阵的结果
xx = 1:1:10;
yy = 0:0.01:1;
lenx = length(xx);
leny = length(yy);
z = zeros(lenx,leny);
for i=1:lenx
    z(i,:) = factorial(n)./ (factorial(n-i).*factorial(i) ).* yy.^(i+a-1).*(1-yy).^(n-i+b-1);
end

%% getHist函数如下:
function myhist = getHist(sample,x,y,dx,dy)
%% 产生二维直方图
%Input:
%    sample:样本,Nx2
%       x  : x方向上的间隔大小
%       y  : y方向上的间隔大小
%      dx  : x方向上的间隔
%      dy  : y方向上的间隔
%Output:
%       myhist:一个二维数组
if nargin < 4
    dx = x(1);
    dy = y(2);
end
row = length(x);
col = length(y);
fx = x(1);
fy = y(1);
myhist = zeros(row,col);
len = length(sample);
for i=1:len
     sx = sample(i,1);
     sy = sample(i,2);
     tx = ceil((sx - fx)/dx) +1 ;
     ty = ceil((sy - fy)/dy) ;
     myhist(tx,ty) = myhist(tx,ty) + 1 ;
end
myhist = myhist./len;
最后贴一个图来看看采样器的结果:
这是采样器模拟出来的结果。
这是分布函数的曲线
当然可以看出其实在图上表现的有很大的不同,这主要是样本数据少,再有就是在统计直方图时,格子宽度的选取问题。以致不能得到平滑的曲线图。(自己的臆断!)
其中介绍一篇非常好的论文:《Markov Chain Monte Carlo and Gibbs Sampling》Lecture Notes for EEB 581, version 26 April 2004°c B. Walsh 2004。
发布了31 篇原创文章 · 获赞 9 · 访问量 3万+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章