2013-09-24 74 views
8

關於如何使用PyMC將兩個Normal分佈擬合爲數據,有a question on CrossValidated。的Cam.Davidson.Pilon答案是使用伯努利分佈數據分配到兩條法線之一:如何在PyMC中建模3個法線的混合物?

size = 10 
p = Uniform("p", 0 , 1) #this is the fraction that come from mean1 vs mean2 
ber = Bernoulli("ber", p = p, size = size) # produces 1 with proportion p. 
precision = Gamma('precision', alpha=0.1, beta=0.1) 

mean1 = Normal("mean1", 0, 0.001) 
mean2 = Normal("mean2", 0, 0.001) 

@deterministic 
def mean(ber = ber, mean1 = mean1, mean2 = mean2): 
    return ber*mean1 + (1-ber)*mean2 

現在我的問題是:如何與法線辦呢?

基本上,問題是你不能再使用伯努利分佈和1伯努利。但如何做到這一點呢?


編輯:隨着CDP的建議下,我寫了下面的代碼:

import numpy as np 
import pymc as mc 

n = 3 
ndata = 500 

dd = mc.Dirichlet('dd', theta=(1,)*n) 
category = mc.Categorical('category', p=dd, size=ndata) 

precs = mc.Gamma('precs', alpha=0.1, beta=0.1, size=n) 
means = mc.Normal('means', 0, 0.001, size=n) 

@mc.deterministic 
def mean(category=category, means=means): 
    return means[category] 

@mc.deterministic 
def prec(category=category, precs=precs): 
    return precs[category] 

v = np.random.randint(0, n, ndata) 
data = (v==0)*(50+ np.random.randn(ndata)) \ 
     + (v==1)*(-50 + np.random.randn(ndata)) \ 
     + (v==2)*np.random.randn(ndata) 
obs = mc.Normal('obs', mean, prec, value=data, observed = True) 

model = mc.Model({'dd': dd, 
       'category': category, 
       'precs': precs, 
       'means': means, 
       'obs': obs}) 

具有以下抽樣程序的痕跡好看也。解決了!

mcmc = mc.MCMC(model) 
mcmc.sample(50000,0) 
mcmc.trace('means').gettrace()[-1,:] 

回答

6

有一個mc.Categorical對象,只是這樣做。

p = [0.2, 0.3, .5] 
t = mc.Categorical('test', p) 
t.random() 
#array(2, dtype=int32) 

它返回一個介於0和len(p)-1之間的整數。要建模3個法線,您可以使p爲對象(它接受長度數組爲k作爲超參數;將數組中的值設置爲相同,即將先驗概率設置爲相等)。模型的其餘部分幾乎完全相同。

這是我上面建議的模型的一般化。


更新:

好了,所以反而有不同的方法,我們可以摺疊他們都爲1:

means = Normal("means", 0, 0.001, size=3) 

... 

@mc.deterministic 
def mean(categorical=categorical, means = means): 
    return means[categorical] 
+0

謝謝。我想到了分類和dirichlet,令我困惑的是'return ber * mean1 +(1-ber)* mean2'的含義。我用提案更新了這個問題,你能告訴我這是否是正確的方法嗎? –

+0

@ user538603已更新! –

+0

好的,這確實有幫助。我添加了一個完整的代碼示例,我在您的幫助下提出了這個示例,但它仍然沒有按照它應該的方式收斂。 –

相關問題