PyMC: выборка шаг за шагом?

Я хотел бы знать, почему сэмплер невероятно медленный при пошаговой выборке. Например, если я запускаю:

mcmc = MCMC(model)
mcmc.sample(1000)

выборка быстрая. Однако, если я запускаю:

mcmc = MCMC(model)
for i in arange(1000):
    mcmc.sample(1)

выборка медленнее (и чем больше выборок, тем медленнее).

Если вам интересно, почему я это спрашиваю... ну, мне нужна пошаговая выборка, потому что я хочу выполнять некоторые операции со значениями переменных после каждого шага сэмплера.

Есть ли способ ускорить его?

Заранее спасибо!

------------------ РЕДАКТИРОВАТЬ ------------------------------- ------------------------------

Здесь я представляю конкретную проблему более подробно:

У меня есть две конкурирующие модели, и они являются частью более крупной модели, в которой есть категориальная переменная, функционирующая как «переключатель» между ними.

В этом игрушечном примере у меня есть наблюдаемый вектор Y, который можно объяснить распределением Пуассона или геометрическим распределением. Категориальная переменная «switch_model» выбирает геометрическую модель, когда = 0, и модель Пуассона, когда = 1.

После каждой выборки, если switch_model выбирает геометрическую модель, я хочу, чтобы переменные модели Пуассона НЕ обновлялись, потому что они не влияют на вероятность и, следовательно, просто уходят. Обратное верно, если модель switch_model выбирает модель Пуассона.

В основном то, что я делаю на каждом шаге, — это «изменение» значения невыбранной модели, возвращая ее вручную на один шаг назад.

Я надеюсь, что мое объяснение и закомментированный код будут достаточно понятными. Дайте мне знать, если вам нужна дополнительная информация.

import numpy as np
import pymc as pm
import pandas as pd
import matplotlib.pyplot as plt

# OBSERVED VALUES
Y = np.array([0, 1, 2, 3, 8])

# PRIOR ON THE MODELS
pi = (0.5, 0.5)

switch_model = pm.Categorical("switch_model", p = pi) 
# switch_model = 0 for Geometric, switch_model = 1 for Poisson

p = pm.Uniform('p', lower = 0, upper = 1) # Prior of the parameter of the geometric distribution
mu = pm.Uniform('mu', lower = 0, upper = 10) # Prior of the parameter of the Poisson distribution


# LIKELIHOOD
@pm.observed
def Ylike(value = Y, mu = mu, p = p, M = switch_model):
    if M == 0:
        out = pm.geometric_like(value+1, p)
    elif M == 1:
        out = pm.poisson_like(value, mu)
    return out

model = pm.Model([Ylike, p, mu, switch_model])

mcmc = pm.MCMC(model)

n_samples = 5000

traces = {}
for var in mcmc.stochastics:
    traces[str(var)] = np.zeros(n_samples)


bar = pm.progressbar.progress_bar(n_samples)
bar.update(0)

mcmc.sample(1, progress_bar=False)
for var in mcmc.stochastics:
    traces[str(var)][0] = mcmc.trace(var)[-1]


for i in np.arange(1,n_samples):
    mcmc.sample(1, progress_bar=False)
    bar.update(i)
    for var in mcmc.stochastics:
        traces[str(var)][i] = mcmc.trace(var)[-1]
    if mcmc.trace('switch_model')[-1] == 0: # Gemetric wins
        traces['mu'][i] = traces['mu'][i-1] # One step back for the sampler of the Poisson parameter
        mu.value = traces['mu'][i-1]

    elif mcmc.trace('switch_model')[-1] == 1: # Poisson wins
        traces['p'][i] = traces['p'][i-1] # One step back for the sampler of the Geometric parameter
        p.value = traces['p'][i-1]

print '\n\n'

traces=pd.DataFrame(traces)

traces['mu'][traces['switch_model'] == 0] = np.nan
traces['p'][traces['switch_model'] == 1] = np.nan

print traces.describe()

traces.plot()
plt.show()

person p.paolo321    schedule 22.03.2014    source источник


Ответы (2)


Причина, по которой это так медленно, заключается в том, что циклы Python for довольно медленные, особенно по сравнению с циклами FORTRAN (на котором в основном написан PyMC). Если бы вы могли показать более подробный код, было бы легче увидеть, что вы делаете. пытаются сделать и предоставить более быстрые альтернативные алгоритмы.

person Broseph    schedule 22.03.2014
comment
Спасибо за ваш ответ. Я добавил игрушечный пример, чтобы объяснить мою проблему. Просто чтобы уточнить, внутри цикла for все операции после mcmc.sample(1) вообще не занимают много времени. По сути, их удаление просто сокращает время на 10%, что ничто по сравнению с тем, насколько длиннее цикл for по сравнению с образцом (10000) - person p.paolo321; 23.03.2014
comment
Я предполагаю, что изменение mu.value и p.value меняет результат следующего вызова mcmc.sample? - person Broseph; 23.03.2014
comment
Да, в самом деле. Поскольку сэмплер представляет собой цепь Маркова, изменение mu.value и p.value влияет на следующий вызов mcmc.sample. - person p.paolo321; 23.03.2014
comment
так что, поскольку результат каждой выборки зависит от результата предыдущей выборки, вы не можете использовать mcmc.sample(5000) для ускорения процесса. Возможно, вы сможете немного ускорить его, если заставите цикл работать со списком, но когда дело доходит до вашего алгоритма, я, честно говоря, недостаточно хорошо разбираюсь в статистике, чтобы сказать, как его изменить. - person Broseph; 23.03.2014
comment
Да, к сожалению, по этой причине я не могу использовать mcmc.sample(5000). Обходной путь может заключаться в том, чтобы сказать сэмплеру НЕ производить выборку из 'mu', если 'switch_model' является геометрическим, и НЕ выполнять выборку из p, если 'switch_model' является пуассоновским. Но я бы не знал, как это сделать.. Все равно спасибо! - person p.paolo321; 23.03.2014

На самом деле я нашел «сумасшедшее» решение, и я подозреваю, что знаю, почему оно работает. Я все еще хотел бы получить экспертное мнение о моем трюке.

По сути, если я изменю цикл for следующим образом, добавив «сброс mcmc» каждые 1000 циклов, выборка снова запустится:

for i in np.arange(1,n_samples):
    mcmc.sample(1, progress_bar=False)
    bar.update(i)
    for var in mcmc.stochastics:
        traces[str(var)][i] = mcmc.trace(var)[-1]
    if mcmc.trace('switch_model')[-1] == 0: # Gemetric wins
        traces['mu'][i] = traces['mu'][i-1] # One step back for the sampler of the Poisson parameter
        mu.value = traces['mu'][i-1]

    elif mcmc.trace('switch_model')[-1] == 1: # Poisson wins
        traces['p'][i] = traces['p'][i-1] # One step back for the sampler of the Geometric parameter
        p.value = traces['p'][i-1]

    if i%1000 == 0:
        mcmc = pm.MCMC(model)

На практике этот трюк стирает трассы и базу данных сэмплера каждые 1000 шагов. Похоже сэмплер не любит длинную базу, хотя я не очень понимаю почему. (Конечно, 1000 шагов являются произвольными, слишком короткие добавляют слишком много накладных расходов, слишком длинные приводят к тому, что трассировки и база данных становятся слишком длинными).

Я нахожу этот хак немного сумасшедшим и определенно не элегантным. Есть ли у кого-нибудь из экспертов или разработчиков комментарий по этому поводу? Благодарю вас!

person p.paolo321    schedule 23.03.2014