Как мне отформатировать наблюдаемые данные для использования в байесовских сетях в pymc3?

Я изо всех сил пытаюсь понять, как наблюдаемые данные работают в pymc3. Из информации, которую я нашел до сих пор, эти два примера оказались наиболее полезными для меня, но я не могу заставить свою модель Работа.

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

import numpy as np
import pymc3 as pm
from theano import shared

no_of_root_categories = 5
no_of_samples = 1000
hot_day = np.random.randint(no_of_root_categories, size=no_of_samples)
option_labels = ["Main", "Side", "Beverage"]
meal_options = np.random.randint(2, size=(len(option_labels), no_of_samples))

Я хочу смоделировать его как простую байесовскую сеть, например:

Байесовская сетевая модель

где наблюдаются заштрихованные узлы.

Вот что у меня есть:

with pm.Model() as crashing_model:
    shape = (no_of_samples, no_of_root_categories)
    alpha = (1 / no_of_root_categories) * np.ones(shape)
    root_prior = pm.Dirichlet("Temperature Rating Prior", alpha, shape=shape)
    root = pm.Categorical('Temperature Rating', p=root_p, shape=no_of_samples, observed=hot_day)

    for item, label in enumerate(option_labels):
        node_data = meal_options[item, :]
        theano_probs = shared(np.array(node_probs))
        node_prior = pm.Beta(f"{label} Prior",
                             mu=root,
                             sigma=root,
                             shape=no_of_samples,
                             testval=np.random.randint(1, size=no_of_samples))
        pm.Binomial(label, p=node_prior, n=no_of_samples, observed=node_data)

который работает, но когда я пытаюсь

with crashing_model:
    trace = pm.sample(1000, random_seed=0)

Python завершается с ошибкой «Плохая начальная энергия».

Я могу создать модель, которая, кажется, работает без скрытых переменных.

with pm.Model() as working_model: # seems to work
    root_values = [np.where(hot_day == i)[0].tolist() for i in range(no_of_root_categories)]
    root_p = [len(i) / 1000 for i in root_values]
    root = pm.Categorical('Temperature Rating', p=root_p)

    shared_proportions = shared(np.array([len(hot_day[i]) for i in root_values]))
    for item, label in enumerate(option_labels):
        node_probs = [sum([meal_options[item, idx] for idx in category]) / len(category) for category in root_values]
        theano_probs = shared(np.array(node_probs))
        pm.Binomial(label, p=theano_probs[root], n=shared_proportions[root])

но я не уверен, как перевести то, что я там сделал, для работы со скрытыми переменными. Любая помощь будет оценена.


person Elenchus    schedule 25.07.2020    source источник


Ответы (1)


С некоторой помощью pymc3 Discourse я получил это работает. Каким-то образом у меня возникла идея, что мне нужно убедиться, что все формы одинаковы, но мне совсем не нужно было их указывать. Код ниже для всех, у кого проблемы.

with pm.Model() as model:
    shape = (no_of_samples, no_of_root_categories)
    alpha = np.ones(no_of_root_categories)
    root_prior = pm.Dirichlet("Temperature Rating Prior", alpha)
    root = pm.Categorical('Temperature Rating', p=root_p, observed=hot_day)

    for item, label in enumerate(option_labels):
        node_data = meal_options[item, :]
        theano_alpha_probs = shared(np.ones(no_of_root_categories))
        theano_beta_probs = shared(np.ones(no_of_root_categories))
        node_prior = pm.Beta(f"{label} Prior",
                             alpha=theano_alpha_probs[root],
                             beta=theano_beta_probs[root],
                             testval=0.5)
        pm.Bernoulli(label, p=node_prior, observed=node_data)
person Elenchus    schedule 26.07.2020