2013-09-24 6 views
8

PyMCを使用してデータに2つの正規分布を当てはめる方法については、a question on CrossValidatedがあります。 Cam.Davidson.Pilonの答えは2面の法線のいずれかにデータを割り当てるために、ベルヌーイ分布を使用していた: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法線をモデル化するには、をmc.Dirichletオブジェクトにします(これは、ハイパーパラメータとしてkの長さの配列を受け入れます;配列の値を同じにすることは、前の確率を等しくすることです)。残りのモデルはほぼ同じです。

これは、私が上で提案したモデルの一般化です。


更新:

わかりましたので、代わりに別の手段を有していると、私たちは1にそれらのすべてを折りたたむことができます。

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

... 

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

ありがとうございました。私はカテゴリとディリクレを考えました。私を混乱させるものは、 'return ber * mean1 +(1-ber)* mean2'の行に入れるべきものです。私は提案で質問を更新しました。これが正しい方法であるかどうか教えてください。 –

+0

@ user538603更新しました! –

+0

さて、それは助けになります。私はあなたの助けを思いついた完全なコード例を追加しましたが、それはまだ収斂していません。 –

関連する問題