如何建立三倍掷硬币的贝叶斯仿真模型

时间:2019-02-13 17:38:39

标签: python bayesian pymc3 mcmc

想象一下,我们扔了8次偏斜的硬币(我们不知道它有多偏斜),到目前为止,我们记录了5个正面(H)至3个反面(T)。接下来的3次抛掉都是尾巴的概率是多少?换句话说,我们想知道在第11次抛掷后出现5H和6T的预期概率。

我想使用pyMC3建立MCMC仿真模型以找到贝叶斯解决方案。贝叶斯方法中也有针对此问题的解析解决方案。因此,我将能够比较从仿真,分析方法以及经典的最常用方法得出的结果。让我简要解释一下到目前为止我可以做什么:

  1. 最常见的解决方案:

如果我们考虑一次抛球的可能性: E(T)= p =(3/8)= 0,375 那么,最终答案是E({T,T,T})= p ^ 3 =(3/8)^ 3 = 0,052。

2.1。贝叶斯分析方法:

请假定未知参数“ p”代表硬币的偏差。 如果我们考虑一次抛球的可能性: E(T)=积分0-1 [p * P(p | H = 5,T = 3)dp] = 0,400(我通过一些代数运算得出了结果) 同样,最终答案是: E({T,T,T})=积分0-1 [p ^ 3 * P(p | H = 5,T = 3)dp] = 10/11 = 0,909。

2.2。具有MCMC模拟的贝叶斯解决方案: 当我们考虑一次抛球的可能性时,我在pyMC3中构建了如下模型:

Head: 0 
Tail: 1
data = [0, 0, 0, 0, 0, 1, 1, 1]
import pymc3 as pm

with pm.Model() as coin_flipping:
    p = pm.Uniform(‘p’, lower=0, upper=1)
    y = pm.Bernoulli(‘y’, p=p, observed=data)
    trace = pm.sample(1000)
    pm.traceplot(trace)

运行这段代码后,我发现后验均值为E(T)= 0,398,非常接近解析解的结果(0,400)。到目前为止,我很高兴,但这不是最终的答案。我需要一个模型来模拟E({T,T,T})的概率。如果有人在此步骤上为我提供帮助,我将非常感激。

1 个答案:

答案 0 :(得分:1)

一种凭经验进行此操作的方法是使用PyMC3的后验预测采样。也就是说,一旦进行了后验采样,就可以从模型的随机参数化生成采样。 pymc3.sample_posterior_predictive()方法将生成与原始观测数据大小相同的新样本。由于您只对三个翻转感兴趣,因此我们可以忽略它生成的其他翻转。例如,如果您想要10000个随机的预测翻转集,则可以这样做

with pm.Model() as coin_flipping:
    # this is still uniform, but I always prefer Beta for proportions
    p = pm.Beta(‘p’, alpha=1, beta=1)

    pm.Bernoulli(‘y’, p=p, observed=data)

    # chains looked a bit waggly at 1K; 10K looks smoother
    trace = pm.sample(10000, random_seed=2019, chains=4)

    # note this generates (10000, 8) observations
    post_pred = pm.sample_posterior_predictive(trace, samples=10000, random_seed=2019)

然后我们可以查看接下来的三个翻转(1,1,1)的频率

np.mean(np.sum(post_pred['y'][:,:3], axis=1) == 3)
# 0.0919

分析解决方案

在此示例中,由于我们具有分析后验预测分布(Beta-Binomial[k | n, a=4, b=6]-有关详细信息,请参见the Wikipedia table of conjugate distributions),因此我们可以准确计算出在接下来的三个翻转中观察到三个尾巴的概率,如下所示:

from scipy.special import comb, beta as beta_fn

n, k = 3, 3  # flips, tails
a, b = 4, 6  # 1 + observed tails, 1 + observed heads

comb(n, k) * beta_fn(n + a, n - k + b) / beta_fn(a, b)
# 0.09090909090909091

请注意,beta_fnEuler Beta function,与Beta版本不同。