目标是从已知参数的分布中获取样本。
例如,自定义分布为p(X | theta),其中theta为K维的参数矢量,X为N维的随机矢量。
现在我们知道(1)theta是已知的; (2)p(X | theta)未知,但我知道p(X | theta)∝ f(X,theta),f是已知函数。
pymc3可以从p(X | theta)进行这种采样吗?
目的不是从参数的后验分布中采样,而是要从自定义分布中采样。
从一个简单的伯努利分布抽样示例开始。我做了以下事情:
import pymc3 as pm
import numpy as np
import scipy.stats as stats
import pandas as pd
import theano.tensor as tt
with pm.Model() as model1:
p=0.3
density = pm.DensityDist('density',
lambda x1: tt.switch( x1, tt.log(p), tt.log(1 - p) ),
) #tt.switch( x1, tt.log(p), tt.log(1 - p) ) is the log likelihood from pymc3 source code
with model1:
step = pm.Metropolis()
samples = pm.sample(1000, step=step)
我希望结果是1000个二进制数字,其中1的比例约为0.3。但是,在输出中出现大量数字的情况下,我得到了奇怪的结果。
我知道出了点问题。请为如何正确地为此类非后置MCMC采样问题编写pymc3代码提供帮助。
答案 0 :(得分:1)
先前的预测采样(您应该使用pm.sample_prior_predictive()
)仅涉及使用计算图中RandomVariable
对象提供的RNG。默认情况下,DensityDist
不实现RNG,但是为此目的提供了random
参数,因此您需要使用它。对数似然率仅针对可观察对象进行评估,因此在这里不起作用。
为任意分布生成有效RNG的一种简单方法是使用inverse transform sampling。在这种情况下,可以对单位间隔上的均匀分布进行采样,然后通过所需函数的逆CDF对其进行变换。对于伯努利情况,逆CDF根据成功概率对单位线进行划分,将0分配给一个零件,将1分配给另一零件。
这是一种类似于工厂的实现,它创建与pm.DensityDist
的{{1}}参数兼容的Bernoulli RNG(即,接受random
和point
kwarg)。
size
因此,要填写示例,它将类似于
def get_bernoulli_rng(p=0.5):
def _rng(point=None, size=1):
# Bernoulli inverse CDF, given p (prob of success)
_icdf = lambda q: np.uint8(q < p)
return _icdf(pm.Uniform.dist().random(point=point, size=size))
return _rng
很显然,这可以同样地用with pm.Model() as m:
p = 0.3
y = pm.DensityDist('y', lambda x: tt.switch(x, tt.log(p), tt.log(1-p)),
random=get_bernoulli_rng(p))
prior = pm.sample_prior_predictive(random_seed=2019)
prior['y'].mean() # 0.306
完成,但是上面给出了一个通用的例子,给出了逆CDF,即只要修改random=pm.Bernoulli.dist(p).random
且参数。