MCMC ve PyMC ile 2-Gauss karışım modeli çıkarımı


10

Sorun

Basit bir 2-Gauss karışım popülasyonunun model parametrelerine uymak istiyorum. Bayesian yöntemleri çevresindeki tüm hype göz önüne alındığında, bu sorun için Bayesian çıkarım geleneksel uydurma yöntemleri daha iyi bir araç olup olmadığını anlamak istiyorum.

Şimdiye kadar MCMC bu oyuncak örneğinde çok kötü bir performans sergiliyor, ancak belki de bir şeyleri göz ardı ettim. Şimdi kodu görelim.

Aletler

Python (2.7) + scipy yığını, lmfit 0.8 ve PyMC 2.3 kullanacağım.

Analizi yeniden üretmek için bir not defteri burada bulunabilir

Verileri oluşturun

Öncelikle veriyi üretelim:

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])

samplesGörünüşün histogramı şöyle:

veri histogramı

"geniş bir tepe noktası" ise, bileşenlerin gözle tespit edilmesi zordur.

Klasik yaklaşım: histograma sığdır

Önce klasik yaklaşımı deneyelim. Lmfit kullanarak 2 uçlu bir model tanımlamak kolaydır:

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'

Son olarak, modeli simpleks algoritmasıyla uyarlıyoruz:

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

Sonuç aşağıdaki görüntüdür (kırmızı kesik çizgiler takılmış merkezlerdir):

NLS uyum sonuçları

Sorun biraz zor olsa bile, uygun başlangıç ​​değerleri ve kısıtlamaları ile modeller oldukça makul bir tahmine dönüştü.

Bayesci yaklaşım: MCMC

Modeli PyMC'de hiyerarşik olarak tanımlıyorum. centersve sigmas2 Gaussluların 2 merkezini ve 2 sigmasını temsil eden hiperparametrelerin öncelikli dağılımıdır. alphailk nüfusun oranıdır ve önceki dağılım burada bir Beta'dır.

Kategorik bir değişken iki popülasyon arasında seçim yapar. Bu değişkenin verilerle ( samples) aynı boyutta olması gerektiğine inanıyorum .

Son olarak muve tauNormal dağılımın parametrelerini belirleyen deterministik değişkenlerdir ( categorydeğişkene bağlıdırlar, böylece iki popülasyon için iki değer arasında rastgele geçiş yaparlar).

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])

Sonra MCMC'yi oldukça uzun sayıda yineleme ile çalıştırıyorum (makinemde 1e5, ~ 60s):

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

Ancak sonuçlar çok garip. Örneğin, trace (ilk popülasyonun oranı) 0.4'e yaklaşmak yerine 0'a eğilimlidir ve çok güçlü bir otokorelasyona sahiptir:α

MCMC alfa özeti

Ayrıca Gauss'luların merkezleri de birbirine yaklaşmıyor. Örneğin:

MM merkezleri_0 özeti

Önceki seçimde gördüğünüz gibi, MCMC algoritmasına önceki popülasyon kısmı için bir Beta dağıtımı kullanarak "yardım etmeye" çalıştım . Ayrıca merkezler ve sigmalar için önceki dağılımlar oldukça makul (bence).α

Peki burada neler oluyor? Yanlış bir şey mi yapıyorum veya MCMC bu sorun için uygun değil mi?

MCMC yönteminin daha yavaş olacağını anlıyorum, ancak önemsiz histogram uyumu, popülasyonları çözmede çok daha iyi performans gösteriyor gibi görünüyor.

Yanıtlar:


6

Sorun, PyMC'nin bu model için örnek çekme yönteminden kaynaklanmaktadır. PyMC belgelerinin 5.8.1 bölümünde açıklandığı gibi , bir dizi değişkeninin tüm elemanları birlikte güncellenir. Bunun gibi küçük diziler centeriçin bir sorun değildir, ancak categorybunun gibi büyük bir dizi için düşük bir kabul oranına yol açar. Kabul oranını şu adresten görebilirsiniz:

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

Belgelerde önerilen çözüm, bir dizi skaler değerli değişken kullanmaktır. Ayrıca, varsayılan seçenekler kötü olduğu için bazı teklif dağıtımlarını yapılandırmanız gerekir. İşte benim için çalışan kod:

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_sdVe proposal_distributionseçenekler açıklanmıştır bölüm 5.7.1 . Merkezler için, öneri, veri miktarı nedeniyle varsayılandan çok daha küçük olan posteriorun standart sapmasına kabaca uyacak şekilde ayarladım. PyMC teklifin genişliğini ayarlamaya çalışır, ancak bu yalnızca kabul oranınız başlamak için yeterince yüksekse işe yarar. Çünkü category, proposal_distribution = 'Poisson'kötü sonuçlar veren varsayılan (bunun neden olduğunu bilmiyorum, ama kesinlikle bir ikili değişken için mantıklı bir teklif gibi görünmüyor).


Teşekkürler, neredeyse dayanılmaz derecede yavaş olmasına rağmen bu gerçekten yararlıdır. Kısaca anlamı açıklayabilir proposal_distributionve proposal_sdve neden kullanılarak Priorkategorik değişkenler için iyidir?
user2304916

Teşekkürler, Tom. Burada Poisson'un garip bir seçim olduğunu kabul ediyorum. Bir sorun açtım: github.com/pymc-devs/pymc/issues/627
twiecki

2

bir Normal ile modellememelisiniz , bu şekilde standart varyasyon için negatif değerlere izin verirsiniz. Bunun yerine aşağıdakini kullanın:σ

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

Güncelleme:

Modelinizin bu bölümlerini değiştirerek verilerin ilk parametrelerine yaklaştım:

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

ve mcmc'yi biraz incelterek çağırarak:

mcmc.sample(200000, 3000, 10)

Sonuçlar:

alfa

merkezleri

sigma

Posteriorlar çok hoş değil ... HATALAR Kitabının 11.6 bölümünde bu tür bir modeli tartışıyorlar ve açık bir çözümü olmayan yakınsama problemleri olduğunu belirtiyorlar. Ayrıca buradan kontrol edin .


Bu iyi bir nokta, şimdi bir Gamma kullanıyorum. Bununla birlikte alfa izi her zaman 0'a eğilimlidir (0.4 yerine). Örneğimde gizlenen bir aptal böcek var mı acaba?
user2304916

Gamma'yı (.1, .1) denedim ama Exp (.1) daha iyi çalışıyor gibi görünüyor. Ayrıca, otokorelasyon yüksek olduğunda, biraz inceltme içerebilir, örneğin,mcmc.sample(60000, 3000, 3)
jpneto

2

Ayrıca, tanımlanamayan karışım modelleri için MCMC kullanımı için büyük bir problemdir. Temel olarak, küme araçlarınızdaki ve küme atamalarınızdaki etiketleri değiştirirseniz, olasılık değişmez ve bu, örnekleyiciyi karıştırabilir (zincirler arasında veya zincirler içinde). Bunu hafifletmeye çalışabileceğiniz bir şey PyMC3'te Potansiyelleri kullanmaktır . Potansiyeller ile bir GMM'nin iyi bir uygulaması burada . Bu tür problemlerin posterioru da genellikle çok modludur ve bu da büyük bir sorun oluşturur. Bunun yerine EM (veya Varyasyonel çıkarım) kullanmak isteyebilirsiniz.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.