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])
samples
Görünüşün histogramı şöyle:
"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):
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. centers
ve sigmas
2 Gaussluların 2 merkezini ve 2 sigmasını temsil eden hiperparametrelerin öncelikli dağılımıdır. alpha
ilk 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 mu
ve tau
Normal dağılımın parametrelerini belirleyen deterministik değişkenlerdir ( category
değ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:
Ayrıca Gauss'luların merkezleri de birbirine yaklaşmıyor. Örneğin:
Ö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.
proposal_distribution
veproposal_sd
ve neden kullanılarakPrior
kategorik değişkenler için iyidir?