2-гауссова модель суміші з MCMC та PyMC


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 легко визначити модель з двома піками:

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і sigmasє пріором розподілу для гіперпараметрів, що представляють 2 центри та 2 сигми двох гауссів. 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)

α

Підсумок альфа-MCMC

Також центри гауссів також не сходяться. Наприклад:

Підсумок центрів MCMC_0

α

То що тут відбувається? Я щось роблю неправильно або MCMC не підходить для цієї проблеми?

Я розумію, що метод MCMC буде повільнішим, але тривіальна гістограма, схоже, працює набагато краще у вирішенні популяцій.

Відповіді:


6

Проблема викликана тим, що PyMC малює зразки для цієї моделі. Як пояснено в розділі 5.8.1 документації PyMC, всі елементи змінної масиву оновлюються разом. Для таких малих масивів 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_distributionі proposal_sdі чому використання Priorкраще для категоріальних змінних?
user2304916

Спасибі, Томе. Я погоджуюся, що Пуассон - це незвичайний вибір. Я відкрив випуск: github.com/pymc-devs/pymc/isissue/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)

результати:

альфа

центри

сигми

Плакати не дуже приємні ... У розділі 11.6 Книги про помилки вони обговорюють цей тип моделі та заявляють, що існують проблеми конвергенції без очевидного рішення. Перевірте також тут .


Це хороший момент, я зараз використовую Гамму. Тим не менш, альфа-слід завжди має значення 0 (замість 0,4). Цікаво, чи є в моєму прикладі якась дурна помилка.
user2304916

Я спробував Gamma (.1, .1), але Exp (.1), здається, працює краще. Крім того, коли автокореляція висока, ви можете включити деяке проріджування, наприклад,mcmc.sample(60000, 3000, 3)
jpneto

2

Крім того, неідентифікація є великою проблемою для використання MCMC для моделей сумішей. В основному, якщо ви перемикаєте мітки на кластерні засоби та призначення кластерів, ймовірність не змінюється, і це може заплутати вибірку (між ланцюгами або всередині ланцюгів). Одне, що ви можете спробувати пом'якшити, це використання Potentials в PyMC3. Хороша реалізація GMM з Potentials є тут . Задні для подібних проблем також, як правило, дуже мультимодальні, що також представляє велику проблему. Натомість ви можете використовувати EM (або Варіаційні умовиводи).

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.