在pymc3

时间:2017-12-07 15:29:23

标签: pymc3 mcmc chi-squared model-fitting

我正在尝试使用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)

这是对的吗?在进行之前的测试时,我发现样本似乎只是从先验中抽取出来的。 提前谢谢。

1 个答案:

答案 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的归一化残差的平方求和)