我正在尝试使用PyMC3使模型适合某些观察到的数据。此模型基于外部代码(通过theano.ops.as_op进行接口),并且取决于MCMC进程应该适合的多个参数。由于无法确定外部代码的梯度,我使用Metropolis-Hastings采样器。
我为输入建立了Uniform priors,并使用我的自定义代码生成模型。但是,我想使用卡方统计量(数据模型/ sigma ^ 2的平方和)来比较模拟数据和我的观察结果(3D np.ndarray)以获得对数似然。绘制MCMC样本时,这应导致迹线收敛于每个参数的最佳值。
我的模型在下面的半伪代码中解释(如果这甚至是一个单词):
import pymc3 as pm
#Some stuff setting up the data, preparing some functions etc.
@theano.compile.ops.as_op(itypes=[input types],otypes = [output types])
def make_model(inputs):
#Wrapper to external code to generate simulated data
return simulated data
model = pm.model()
with model:
#priors for 13 input parameters
simData = make_model(inputs)
我现在想要获得此模型与数据的卡方logLikelihood,我认为可以使用pm.ChiSquared完成,但是我没有看到如何将数据,模型和此分布组合在一起导致采样器正确执行。我猜它可能看起来像:
chiSq = pm.ChiSquared(nu=data.size, observed = (data-simData)**2/err**2)
trace = pm.sample(1000)
这是对的吗?在进行之前的测试时,我发现样本似乎只是从先验中抽取出来的。 提前谢谢。
答案 0 :(得分:0)
根据aloctavodia的建议,我能够使用pm.Normal
可能性来获得某些玩具指数数据的参数估计。使用OP提出的pm.ChiSquared
可能性,模型收敛到正确的值,但参数的后验宽度大约是后者的三倍。这是模型的代码;我首先生成数据,然后将其与PyMC3配合使用。
# Draw `nPoints` observed data points `y_obs` from the function
# 3. + 18. * numpy.exp(-.2 * x)
# with the points evaluated at `x_obs`
# x_obs = numpy.linspace(0, 100, nPoints)
# Add Normal(mu=0,sd=`cov`) noise to each point in `y_obs`
# Then instantiate PyMC3 model for fit:
def YModel(x, c, a, l):
# exponential model expected to describe the data
mu = c + a * pm.math.exp(-l * x)
return mu
def logp(y_mod, y_obs):
# Normal distribution likelihood
return pm.Normal.dist(mu = y_mod, sd = cov).logp(y_obs)
# Chi squared likelihood (to use, comment preceding line & uncomment next 2 lines)
#chi2 = chi2 = pm.math.sum( ((y_mod - y_obs)/cov)**2 )
#return pm.ChiSquared.dist(nu = nPoints).logp(chi2)
with pm.Model() as model:
c = pm.Uniform('constant', lower = 0., upper = 10., testval = 5.)
a = pm.Uniform('amplitude', lower = 0., upper = 50., testval = 25.)
l = pm.Uniform('lambda', lower = 0., upper = 10., testval = 5.)
y_mod = YModel(x_obs, c, a, l)
L = pm.DensityDist('L', logp, observed = {'y_mod': y_mod, 'y_obs': y_obs}, testval = {'y_mod': y_mod, 'y_obs': y_obs})
step = pm.Metropolis([c, a, l])
trace = pm.sample(draws = 10000, step = step)
上面的模型收敛了,但是我发现成功对先验的界限和对这些参数的初步猜测很敏感。
mean sd mc_error hpd_2.5 hpd_97.5 n_eff Rhat
c 3.184397 0.111933 0.002563 2.958383 3.397741 1834.0 1.000260
a 18.276887 0.747706 0.019857 16.882025 19.762849 1343.0 1.000411
l 0.200201 0.013486 0.000361 0.174800 0.226480 1282.0 0.999991
(编辑:我忘了对chi2
的归一化残差的平方求和)