PyMC:一步一步抽样?

时间:2014-03-22 18:25:30

标签: pymc mcmc

我想知道为什么采样器在逐步采样时非常慢。 例如,如果我运行:

mcmc = MCMC(model)
mcmc.sample(1000)

采样速度很快。但是,如果我跑:

mcmc = MCMC(model)
for i in arange(1000):
    mcmc.sample(1)

采样速度较慢(采样越多,采样越慢)。

如果你想知道我为什么要问这个......好吧,我需要一步一步的采样,因为我想在采样器的每一步之后对变量的值执行一些操作。

有没有办法加快速度?

提前谢谢!

------------------编辑---------------------------- ---------------------------------

在此,我将详细介绍具体问题:

我在比赛中有两个模型,它们是一个更大型号的一部分,它具有一个分类变量,可以作为一个“开关”。两者之间。

在这个玩具示例中,我有观察到的矢量' Y',可以通过泊松或几何分布来解释。分类变量' switch_model'选择= 0时的几何模型和= 1时的泊松模型。

在每个样本之后,如果switch_model选择几何模型,我希望不更新泊松模型的变量,因为它们不会影响可能性,因此它们正在逐渐消失。如果switch_model选择Poisson模型则相反。

基本上我在每一步所做的就是改变'通过手动将其退回一步,将非选定模型的值。

我希望我的解释和评论代码足够清晰。如果您需要更多详细信息,请与我们联系。

import numpy as np
import pymc as pm
import pandas as pd
import matplotlib.pyplot as plt

# OBSERVED VALUES
Y = np.array([0, 1, 2, 3, 8])

# PRIOR ON THE MODELS
pi = (0.5, 0.5)

switch_model = pm.Categorical("switch_model", p = pi) 
# switch_model = 0 for Geometric, switch_model = 1 for Poisson

p = pm.Uniform('p', lower = 0, upper = 1) # Prior of the parameter of the geometric distribution
mu = pm.Uniform('mu', lower = 0, upper = 10) # Prior of the parameter of the Poisson distribution


# LIKELIHOOD
@pm.observed
def Ylike(value = Y, mu = mu, p = p, M = switch_model):
    if M == 0:
        out = pm.geometric_like(value+1, p)
    elif M == 1:
        out = pm.poisson_like(value, mu)
    return out

model = pm.Model([Ylike, p, mu, switch_model])

mcmc = pm.MCMC(model)

n_samples = 5000

traces = {}
for var in mcmc.stochastics:
    traces[str(var)] = np.zeros(n_samples)


bar = pm.progressbar.progress_bar(n_samples)
bar.update(0)

mcmc.sample(1, progress_bar=False)
for var in mcmc.stochastics:
    traces[str(var)][0] = mcmc.trace(var)[-1]


for i in np.arange(1,n_samples):
    mcmc.sample(1, progress_bar=False)
    bar.update(i)
    for var in mcmc.stochastics:
        traces[str(var)][i] = mcmc.trace(var)[-1]
    if mcmc.trace('switch_model')[-1] == 0: # Gemetric wins
        traces['mu'][i] = traces['mu'][i-1] # One step back for the sampler of the Poisson parameter
        mu.value = traces['mu'][i-1]

    elif mcmc.trace('switch_model')[-1] == 1: # Poisson wins
        traces['p'][i] = traces['p'][i-1] # One step back for the sampler of the Geometric parameter
        p.value = traces['p'][i-1]

print '\n\n'

traces=pd.DataFrame(traces)

traces['mu'][traces['switch_model'] == 0] = np.nan
traces['p'][traces['switch_model'] == 1] = np.nan

print traces.describe()

traces.plot()
plt.show()

2 个答案:

答案 0 :(得分:0)

这个速度太慢的原因是Python的for循环非常慢,特别是当它们与FORTRAN循环进行比较时(这基本上就是PyMC的编写)。如果你能展示更多详细的代码,可能更容易看到你正在尝试做什么,并提供更快的替代算法。

答案 1 :(得分:0)

实际上我找到了一个“疯狂”的解决方案,我怀疑他知道它为什么会起作用。我仍然希望得到关于我的伎俩的专家意见。

基本上如果我按照以下方式修改for循环,每1000次循环添加一次'mcmc'重置,则采样再次启动:

for i in np.arange(1,n_samples):
    mcmc.sample(1, progress_bar=False)
    bar.update(i)
    for var in mcmc.stochastics:
        traces[str(var)][i] = mcmc.trace(var)[-1]
    if mcmc.trace('switch_model')[-1] == 0: # Gemetric wins
        traces['mu'][i] = traces['mu'][i-1] # One step back for the sampler of the Poisson parameter
        mu.value = traces['mu'][i-1]

    elif mcmc.trace('switch_model')[-1] == 1: # Poisson wins
        traces['p'][i] = traces['p'][i-1] # One step back for the sampler of the Geometric parameter
        p.value = traces['p'][i-1]

    if i%1000 == 0:
        mcmc = pm.MCMC(model)

实际上,这个技巧每1000步就会删除采样器的跟踪和数据库。看起来像采样器不喜欢有一个很长的数据库,虽然我真的不明白为什么。 (当然1000步是任意的,太短,它增加了太多的开销,太长时间会导致跟踪和数据库太长)。

我觉得这个黑客有点疯狂,绝对不优雅..有没有专家或开发者对此发表评论?谢谢!