ปัญหา
ฉันต้องการให้พอดีกับพารามิเตอร์แบบจำลองของประชากร 2-Gaussian แบบเรียบง่าย ให้ทุก hype รอบวิธี Bayesian ฉันต้องการเข้าใจว่าสำหรับปัญหานี้อนุมาน Bayesian เป็นเครื่องมือที่ดีกว่าวิธีการกระชับแบบดั้งเดิม
จนถึงตอนนี้ MCMC ทำงานได้แย่มากในตัวอย่างของเล่นนี้ แต่บางทีฉันอาจมองข้ามบางสิ่งบางอย่าง ดังนั้นเรามาดูรหัส
เครื่องมือ
ฉันจะใช้ python (2.7) + scipy stack, 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-peaks:
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()
ผลที่ได้คือภาพต่อไปนี้ (เส้นประสีแดงเป็นจุดศูนย์กลางพอดี):
แม้ว่าปัญหาจะเป็นเรื่องยาก แต่ด้วยค่าเริ่มต้นและข้อ จำกัด ที่เหมาะสมโมเดลก็แปรเปลี่ยนเป็นค่าประมาณที่สมเหตุสมผล
วิธี Bayesian: MCMC
ฉันกำหนดโมเดลใน PyMC ตามลำดับชั้น centers
และsigmas
เป็นการแจกแจงของไฮเปอร์สำหรับไฮเปอร์พารามิเตอร์ที่เป็นตัวแทนของ 2 ศูนย์และ 2 sigmas ของ 2 Gaussians alpha
คือเศษส่วนของประชากรแรกและการกระจายก่อนหน้านี้อยู่ที่นี่เบต้า
ตัวแปรเด็ดขาดเลือกระหว่างประชากรสองคน ฉันเข้าใจว่าตัวแปรนี้ต้องมีขนาดเท่ากันกับข้อมูล ( samples
)
ในที่สุดmu
และtau
เป็นตัวแปรกำหนดที่กำหนดพารามิเตอร์ของการกระจายปกติ (พวกเขาขึ้นอยู่กับcategory
ตัวแปรดังนั้นพวกเขาสุ่มสลับระหว่างค่าสองค่าสำหรับประชากรทั้งสอง)
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, ~ 60s บนเครื่องของฉัน):
mcmc = pm.MCMC(model)
mcmc.sample(100000, 30000)
นอกจากนี้ศูนย์กลางของ Gaussians ก็ไม่มาบรรจบกันเช่นกัน ตัวอย่างเช่น:
แล้วเกิดอะไรขึ้นที่นี่? ฉันกำลังทำอะไรผิดหรือ MCMC ไม่เหมาะสำหรับปัญหานี้หรือไม่?
ฉันเข้าใจว่าวิธีการ MCMC จะช้าลง แต่ฮิสโตแกรมเล็กน้อยนั้นดูเหมือนว่าจะทำงานได้ดีขึ้นอย่างมากในการแก้ปัญหาประชากร
proposal_distribution
และproposal_sd
และเหตุผลที่ใช้Prior
จะดีกว่าสำหรับตัวแปรเด็ดขาด?