pymc3:多个观察值

时间:2014-06-16 11:28:33

标签: python pymc poisson pymc3

我有一些观察数据,我想估计参数,我认为这是一个尝试PYMC3的好机会。

我的数据结构为一系列记录。每条记录包含一对与固定的一小时周期相关的观察结果。一个观察结果是在给定小时内发生的事件总数。另一个观察是该时期内的成功数量。因此,例如,数据点可能指定在给定的1小时内,总共有1000个事件,而1000个事件中的100个是成功的。在另一个时期,总共可能有1000000个事件,其中120000个是成功的。观测值的方差不是恒定的,取决于事件的总数,部分是我想要控制和建模的效果。

我这样做的第一步是估计潜在的成功率。我已经准备好了下面的代码,旨在通过提供两套“观察到的”来模仿这种情况。使用scipy生成数据。但是,它无法正常工作 我期望它找到的是:

  • loss_lambda_factor大致为0.1
  • total_lambda(和total_lambda_mu)大致为120.

相反,模型很快收敛,但意外的回答。

  • total_lambda和total_lambda_mu分别是5e5附近的尖峰。
  • loss_lambda_factor大致为0。

traceplot(由于信誉低于10而无法发布)是相当无趣的 - 快速收敛,以及与输入数据不对应的数字的尖峰。我很好奇我所采用的方法是否存在根本性的错误。如何修改以下代码以提供正确/预期的结果?

from pymc import Model, Uniform, Normal, Poisson, Metropolis, traceplot 
from pymc import sample 
import scipy.stats

totalRates = scipy.stats.norm(loc=120, scale=20).rvs(size=10000)
totalCounts = scipy.stats.poisson.rvs(mu=totalRates) 
successRate = 0.1*totalRates 
successCounts = scipy.stats.poisson.rvs(mu=successRate) 

with Model() as success_model: 
    total_lambda_tau= Uniform('total_lambda_tau', lower=0, upper=100000)
    total_lambda_mu = Uniform('total_lambda_mu', lower=0, upper=1000000)
    total_lambda = Normal('total_lambda', mu=total_lambda_mu, tau=total_lambda_tau)
    total = Poisson('total', mu=total_lambda, observed=totalCounts) 

    loss_lambda_factor = Uniform('loss_lambda_factor', lower=0, upper=1)
    success_rate = Poisson('success_rate', mu=total_lambda*loss_lambda_factor, observed=successCounts) 

with success_model: 
    step =  Metropolis() 
    success_samples = sample(20000, step) #, start)


plt.figure(figsize=(10, 10)) 
_ = traceplot(success_samples)

2 个答案:

答案 0 :(得分:25)

除了任何贝叶斯MCMC分析的缺陷外,你的方法没有根本的错误:(1)非收敛,(2)先验,(3)模型。

非收敛性:我找到一个如下所示的traceplot:

traceplot with burnin included

这不是一件好事,为了更清楚地看到原因,我会更改traceplot代码以仅显示跟踪的后半部分traceplot(success_samples[10000:])

traceplot with burnin removed

先前的:融合的一个主要挑战是你在total_lambda_tau的先验,这是贝叶斯建模的一个典型陷阱。虽然使用之前的Uniform('total_lambda_tau', lower=0, upper=100000)可能看起来很无法提供信息,但这样做的结果是您确信total_lambda_tau很大。例如,它小于10的概率是.0001。改变之前的

total_lambda_tau= Uniform('total_lambda_tau', lower=0, upper=100)
total_lambda_mu = Uniform('total_lambda_mu', lower=0, upper=1000)

导致更有希望的traceplot:

traceplot with different priors

然而,这仍然不是我在traceplot中寻找的东西,为了获得更令人满意的东西,我建议使用“顺序扫描Metropolis”步骤(这是PyMC2默认为类似模型的步骤)。您可以按如下方式指定:

step =  pm.CompoundStep([pm.Metropolis([total_lambda_mu]),
                         pm.Metropolis([total_lambda_tau]),
                         pm.Metropolis([total_lambda]),
                         pm.Metropolis([loss_lambda_factor]),
                         ]) 

这会产生一个似乎可以接受的traceplot:

traceplot with sequential scan metropolis

模型:正如@KaiLondenberg回应的那样,您在total_lambda_tautotal_lambda_mu上使用先验的方法不是标准方法。您描述了各种各样的事件总数(一小时1,000小时,下一小时1,000,000),但您的模型假定它是正态分布的。在空间流行病学中,我在类比数据中看到的方法是更像这样的模型:

import pymc as pm, theano.tensor as T
with Model() as success_model: 
    loss_lambda_rate = pm.Flat('loss_lambda_rate')
    error = Poisson('error', mu=totalCounts*T.exp(loss_lambda_rate), 
            observed=successCounts)

我确信在其他研究社区中还有其他方法似乎更为熟悉。

这是a notebook collecting up these comments

答案 1 :(得分:1)

我看到该模型存在一些潜在问题。

1。)我认为成功计数(称为错误?)应遵循二项式(n = total,p = loss_lambda_factor)分布,而不是泊松。

2)。 连锁从哪里开始?除非使用纯吉布斯采样,否则从MAP或MLE配置开始是有意义的。否则链条可能需要很长时间才能老化,这可能是这里发生的事情。

3。)你选择了total_lambda的层次优先级(即在这些参数上有两个统一先验的正常),确保链条需要很长时间才能收敛,除非你明智地选择你的开头(如第2点所述)。 。你基本上为MCMC链引入了许多不必要的自由度。假设total_lambda必须是非符号的,我会在合适的范围内选择一个Un_ prior / total_lambda(例如从0到观察到的最大值)。

4.。)您使用Metropolis Sampler。 20000个样本可能不足以满足那个样本。尝试60000并将第一个20000丢弃为老化。大都会采样器可能需要一段时间来调整步长,因此很可能花费前20000个样本主要拒绝提议和调整。尝试其他采样器,如NUTS。