@zsh-o
2018-12-16T11:36:13.000000Z
字数 6298
阅读 1135
机器学习
《统计学习方法》
%matplotlib inline
import numpy as np
from matplotlib import pyplot as plt
利用一个容易进行抽样的分布,根据大数定理可以对函数积分进行估计
def f(x):
return 0.3 * np.exp(-(x - 0.3) ** 2) + 0.7 * np.exp(- (x - 2.) ** 2 / 0.3)
## 蒙特卡洛 均值法 求f的积分
def MC(f, low, high, size):
z = np.random.uniform(low=low, high=high, size=size)
return np.sum(f(z) * (high - low)) / size
Int_f = MC(f, -2, 4, 10**6)
Int_f
1.211298965791444
相当于在所围成的区域里面进行抽样,只返回在所围成区域内部的采样点,这样在所围成的区域进行抽样每个抽样点的概率为,表示点处的概率,表示上面的表示在均匀分布进行采样,每个点的概率均是,故这样得到的每个采样点的概率均相同并且等于,相当于的积分,然后根据蒙特卡洛思想,根据判断该点是否应该保留,则被保留的概率为均匀分布中的部分则保留概率为,然后再由点的概率为,故经过该拒绝操作之后点并且被接受的概率为
接受的概率为
因此,总的迭代次数大致为所要样本点数的倍
最后在接受的条件下每个点的概率为
size = 10**4
mean = 1.4
sigma = 1.2
k = 3
## 为了能够使后面的可视化对其曲线,对f(x)进行归一化,用的上面的均值方法
def p(x):
return f(x) / Int_f
def q(x):
return 1 / (sigma * np.sqrt(2 * np.pi)) * np.exp(- (x - mean) ** 2 / (2 * sigma ** 2))
def sample_q():
return np.random.normal(loc=mean, scale=sigma)
def reject_sampling(p, q, sample_q, k, size):
res = []
it = 0
ti = 0
while(it < size):
z = sample_q()
qz = q(z)
u = np.random.uniform(low=0,high=k*qz)
pz = p(z)
if u < pz:
res.append(z)
it += 1
ti += 1
return np.array(res), ti
sample, ti = reject_sampling(p, q, sample_q, k, size)
ti
30031
count, bins, ignored = plt.hist(sample, bins=300,density=True)
plt.plot(bins, p(bins))
plt.plot(bins, k * q(bins))
[<matplotlib.lines.Line2D at 0x15bbd3a0518>]
这部分《LDA数学八卦》写的非常好了,这里只提一下
上面比较麻烦的是的选择,如何消除,MCMC的方法通过消除了
MCMC用了马尔科夫的平稳分布的性质,无论初始概率分布是多少,通过转移矩阵的有限次状态转移后,最终都会收敛到平稳分布,也即
而且
此时有马氏链的状态转移过程表示如下,
先只考虑和,由马氏链有和的联合概率为,因而的边缘概率为
由此,当初始分布为平稳分布时,故是独立同分布的,即使每一步均是从转移矩阵组成的概率里面进行抽样,抽样的边缘概率仍然满足平稳分布,也即每一个抽样点均满足抽样分布,而且当该过程持续到,同理
故,当初始为平稳分布时,故只需要有了平稳分布为要抽样分布的转移矩阵之后,就可以利用每次抽样状态转移的方法得到所要的抽样样本,而且即使初始分布不是平稳分布,由于任意初始分布经过有限步骤状态转移后均变成平稳分布,故抽样时可以是任意初始状态,在一定步骤之后就变成了所要的抽样
接下来问题变成了如何得到平稳分布是所要分布的转移矩阵,直接根据平稳分布构造转移矩阵是非常困难的,大哥们为平稳分布的转移矩阵添加了一个约束使其变得容易构造,该约束就是细致平稳条件
如果非周期马氏链的转移矩阵和分布满足
则是马氏链的平稳分布,上式被称为细致平稳条件
满足细致平稳条件肯定是平稳分布
接下来是如何利用该细致平稳条件构造满足条件的转移矩阵,现有任意分布和任意转移矩阵,为状态,我们来构造
此时的平稳分布即为转移矩阵为
再根据上面的抽样过程,当前状态为,我们要从转移矩阵中抽样得到下一个状态,相当于我们要在分布中抽样,但该分布是不规则的无法直接抽样,但转移概率是任意的,可以选其为合适的容易抽样的概率分布,按照上面拒绝采样的方法就相当于,首先在抽样出状态,然后有的概率接受该样本,应该如何证明在中抽样等价于在,然后再以概率接受该抽样,并且,设抽样为,接受率为,则
这时如果确实是一个关于的概率分布的话,那么,这个地方有点问题。。。
以下面代码中例子为例,,则
故实际迭代次数大致为所求样本个数的倍
同样
def q(y, x): # q(y|x)
return 1/(5. - (-2.5))
def sample_q(x):
return np.random.uniform(low=-2.5, high=5.)
def mcmc(p, q, sample_q, size, base_iter=10**2):
res = []
it = 0
x = 0.
ti = 0
while it < size + base_iter:
y = sample_q(x)
u = np.random.uniform(low=0, high=1)
if u <= p(y)*q(x, y):
x = y
it += 1
res.append(x)
ti += 1
return np.array(res)[base_iter:], ti
x = np.linspace(-2, 4, 10000)
y = p(x)
sample, ti = mcmc(p, q, sample_q, 10**4)
count, bins, ignored = plt.hist(sample, bins=300,density=True)
plt.plot(bins, p(bins))
[<matplotlib.lines.Line2D at 0x15bbf406940>]
ti
561925
由细致平稳条件
def Metropolis_Hastings(p, q, sample_q, size, base_iter=10**2):
res = []
it = 0
x = 0.
ti = 0
while it < size + base_iter:
y = sample_q(x)
u = np.random.uniform(low=0., high=1)
a = min(p(y) / p(x) * q(y, x) / q(x, y), 1)
if u < a:
x = y
it += 1
res.append(x)
ti += 1
return np.array(res)[base_iter:], ti
sample, ti = Metropolis_Hastings(p, q, sample_q, 10**4)
count, bins, ignored = plt.hist(sample, bins=300,density=True)
plt.plot(bins, p(bins))
[<matplotlib.lines.Line2D at 0x15bbf76eb70>]
ti
27495
这个地方需要注意,原始写的有点问题,每次抽样出来的样本都需要加入到总体样本中,这样的话,其跟拒绝采样的不同点在于MCMC不抛弃样本,只根据当前状态判断是否跳转