MCMCおよびPyMCによる2ガウス混合モデルの推論


10

問題

単純な2ガウス混合母集団のモデルパラメーターを近似します。ベイジアン手法をめぐる誇大宣伝を踏まえ、この問題についてベイジアン推論が従来のフィッティング手法よりも優れたツールであるかどうかを理解したいと思います。

これまでのところ、MCMCはこのおもちゃの例ではパフォーマンスが非常に低くなっていますが、おそらく見落としているだけかもしれません。コードを見てみましょう。

道具

私はpython(2.7)+ scipyスタック、lmfit 0.8およびPyMC 2.3を使用します。

分析を再現するためのノートはここにあります

データを生成する

最初にデータを生成してみましょう:

from scipy.stats import distributions

# Sample parameters
nsamples = 1000
mu1_true = 0.3
mu2_true = 0.55
sig1_true = 0.08
sig2_true = 0.12
a_true = 0.4

# Samples generation
np.random.seed(3)  # for repeatability
s1 = distributions.norm.rvs(mu1_true, sig1_true, size=round(a_true*nsamples))
s2 = distributions.norm.rvs(mu2_true, sig2_true, size=round((1-a_true)*nsamples))
samples = np.hstack([s1, s2])

のヒストグラムはsamples次のようになります。

データヒストグラム

「広いピーク」の場合、コンポーネントを目で確認するのは困難です。

古典的なアプローチ:ヒストグラムを当てはめる

最初に古典的なアプローチを試してみましょう。lmfitを使用すると、2ピークモデルを簡単に定義できます。

import lmfit

peak1 = lmfit.models.GaussianModel(prefix='p1_')
peak2 = lmfit.models.GaussianModel(prefix='p2_')
model = peak1 + peak2

model.set_param_hint('p1_center', value=0.2, min=-1, max=2)
model.set_param_hint('p2_center', value=0.5, min=-1, max=2)
model.set_param_hint('p1_sigma', value=0.1, min=0.01, max=0.3)
model.set_param_hint('p2_sigma', value=0.1, min=0.01, max=0.3)
model.set_param_hint('p1_amplitude', value=1, min=0.0, max=1)
model.set_param_hint('p2_amplitude', expr='1 - p1_amplitude')
name = '2-gaussians'

最後に、モデルをシンプレックスアルゴリズムで近似します。

fit_res = model.fit(data, x=x_data, method='nelder')
print fit_res.fit_report()

結果は次の画像です(赤い破線はフィットした中心です):

NLSフィットの結果

問題が少し難しい場合でも、適切な初期値と制約があれば、モデルはかなり合理的な推定値に収束しました。

ベイジアンアプローチ:MCMC

モデルはPyMCで階層的に定義します。centersそしてsigmas2つのセンター及び2つのガウスの2つのシグマを表すハイパーための事前確率分布です。alpha最初の人口の割合であり、以前の分布はここではベータです。

カテゴリー変数は、2つの母集団から選択します。この変数はデータ(samples)と同じサイズである必要があると私は理解しています。

最後mutau(それらが依存正規分布のパラメータを決定する決定論的変数でありcategory、彼らはランダムに2つの集団のための2つの値の間で切り替えるように可変)。

sigmas = pm.Normal('sigmas', mu=0.1, tau=1000, size=2)
centers = pm.Normal('centers', [0.3, 0.7], [1/(0.1)**2, 1/(0.1)**2], size=2)
#centers = pm.Uniform('centers', 0, 1, size=2)

alpha  = pm.Beta('alpha', alpha=2, beta=3)
category = pm.Categorical("category", [alpha, 1 - alpha], size=nsamples)

@pm.deterministic
def mu(category=category, centers=centers):
    return centers[category]

@pm.deterministic
def tau(category=category, sigmas=sigmas):
    return 1/(sigmas[category]**2)

observations = pm.Normal('samples_model', mu=mu, tau=tau, value=samples, observed=True)
model = pm.Model([observations, mu, tau, category, alpha, sigmas, centers])

次に、MCMCを非常に長い反復回数(私のマシンでは1e5、約60秒)で実行します。

mcmc = pm.MCMC(model)
mcmc.sample(100000, 30000)

α

MCMCアルファの概要

また、ガウシアンの中心も収束しません。例えば:

MCMC centre_0概要

α

ここで何が起こっているのでしょうか?私は何か間違ったことをしていますか、それともMCMCはこの問題に適していませんか?

MCMCメソッドは遅くなることは理解していますが、自明なヒストグラムフィットは母集団の解決において非常に優れているようです。

回答:


6

この問題は、PyMCがこのモデルのサンプルを描画する方法が原因で発生します。PyMCドキュメントのセクション5.8.1で説明されているように、配列変数のすべての要素は一緒に更新されます。centerこのような小さなアレイの場合は問題ありませんが、このような大きなアレイのcategory場合は、受け入れ率が低くなります。合格率は

print mcmc.step_method_dict[category][0].ratio

ドキュメントで提案されている解決策は、スカラー値変数の配列を使用することです。また、デフォルトの選択は不適切であるため、いくつかのプロポーザル配信を構成する必要があります。これは私のために働くコードです:

import pymc as pm
sigmas = pm.Normal('sigmas', mu=0.1, tau=1000, size=2)
centers = pm.Normal('centers', [0.3, 0.7], [1/(0.1)**2, 1/(0.1)**2], size=2)
alpha  = pm.Beta('alpha', alpha=2, beta=3)
category = pm.Container([pm.Categorical("category%i" % i, [alpha, 1 - alpha]) 
                         for i in range(nsamples)])
observations = pm.Container([pm.Normal('samples_model%i' % i, 
                   mu=centers[category[i]], tau=1/(sigmas[category[i]]**2), 
                   value=samples[i], observed=True) for i in range(nsamples)])
model = pm.Model([observations, category, alpha, sigmas, centers])
mcmc = pm.MCMC(model)
# initialize in a good place to reduce the number of steps required
centers.value = [mu1_true, mu2_true]
# set a custom proposal for centers, since the default is bad
mcmc.use_step_method(pm.Metropolis, centers, proposal_sd=sig1_true/np.sqrt(nsamples))
# set a custom proposal for category, since the default is bad
for i in range(nsamples):
    mcmc.use_step_method(pm.DiscreteMetropolis, category[i], proposal_distribution='Prior')
mcmc.sample(100)  # beware sampling takes much longer now
# check the acceptance rates
print mcmc.step_method_dict[category[0]][0].ratio
print mcmc.step_method_dict[centers][0].ratio
print mcmc.step_method_dict[alpha][0].ratio

proposal_sdそしてproposal_distributionオプションはで説明されているセクション5.7.1。中心については、事後の標準偏差にほぼ一致するように提案を設定しました。これは、データ量が原因でデフォルトよりはるかに小さくなっています。PyMCは提案の幅を調整しようとしますが、これは、受け入れ率が最初から十分に高い場合にのみ機能します。の場合category、デフォルトproposal_distribution = 'Poisson'では不十分な結果になります(これがなぜなのかはわかりませんが、バイナリ変数の賢明な提案のようには聞こえません)。


ありがとう、これは本当に便利ですが、ほとんど耐えられないほど遅くなります。カテゴリー変数の意味proposal_distributionproposal_sdその理由を簡単に説明できますPriorか?
user2304916 2014年

ありがとう、トム。ここではポアソンが奇妙な選択であることに同意します。問題を公開しました:github.com/pymc-devs/pymc/issues/627
twiecki

2

σ

sigmas = pm.Exponential('sigmas', 0.1, size=2)

更新:

モデルのこれらの部分を変更することで、データの初期パラメーターに近づきました。

sigmas = pm.Exponential('sigmas', 0.1, size=2)
alpha  = pm.Beta('alpha', alpha=1, beta=1)

そして、いくつかの間引きでmcmcを呼び出すことによって:

mcmc.sample(200000, 3000, 10)

結果:

アルファ

センター

シグマ

事後者はあまりよくありません... BUGS Bookのセクション11.6で、このタイプのモデルについて議論し、明確な解決策がない収束問題があると述べています。こちらもチェック。


それは良い点です、私は今ガンマを使用しています。それにもかかわらず、アルファトレースは常に(0.4ではなく)0になる傾向があります。私の例に潜んでいる愚かなバグがあるのだろうか。
user2304916 2014年

Gamma(.1、.1)を試しましたが、Exp(.1)の方がうまくいくようです。また、自己相関が高い場合は、いくつかの間引きを含めることができます。たとえば、mcmc.sample(60000, 3000, 3)
jpneto

2

また、混合モデルにMCMCを使用する場合、識別不能性が大きな問題になります。基本的に、クラスターの平均とクラスターの割り当てでラベルを切り替える場合、可能性は変化せず、これによりサンプラーが(チェーン間またはチェーン内で)混乱する可能性があります。これを軽減しようとするかもしれない1つのことは、PyMC3でポテンシャルを使用することです。ポテンシャルを備えたGMMの適切な実装はこちらです。これらの種類の問題の事後は、一般に非常にマルチモーダルであり、これも大きな問題を提示します。代わりにEM(または変分推論)を使用したい場合があります。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.