Maria
Maria

Reputation: 108

Using Categorical with multi-dimensional p in PyMC3

I am running into problems when I am trying to use pm.Categorical to sample many instances at once (either with multidimensional p or using theano.scan). What is the best way to go here? My goal is to sample one response per draw for each of many individuals, based on the probability of each response for each individual.

Here is a working example for many individuals, one draw:

import pymc3 as pm
import theano.tensor as T
import numpy as np

actions = T.as_tensor_variable(np.array([0, 1, 2]))  # indiv0 selects response0, indiv1 response1, etc.
with pm.Model() as model:
    p = pm.Beta('p', alpha=2, beta=2, shape=[3, 3])  # prob. for each indiv. for each response
    actions = pm.Categorical('actions', p=p, observed=actions)
    trace = pm.sample()

Everything works fine here. The model samples nine p's, one for each individual and each response. But what I'd like to do is to sample several responses for each individual. I first tried to add a dimension of trials to the actions data:

n_trials = 10
actions = T.as_tensor_variable(np.array([[0, 1, 2]] * n_trials))  # same thing, 10 trials
with pm.Model() as model:
    p = pm.Beta('p', alpha=2, beta=2, shape=[3, 3])  # same as above, but more trials
    actions = pm.Categorical('actions', p=p, observed=actions)
    trace = pm.sample()

Obviously, this leads to an error:

Wrong number of dimensions: expected 1, got 2 with shape (10, 3).

Surprisingly, it also leads to an error when I draw a separate p for each sample, each individual, and each response:

p = pm.Beta('p', alpha=2, beta=2, shape=[n_trials, 3, 3])

It seems like pm.Categorical only accepts 2-dimensional p. To keep p 2-dimensional, I tried scanning:

actions = T.as_tensor_variable(np.array([[0, 1, 2]] * 10)
with pm.Model() as model:
    p = pm.Beta('p', alpha=2, beta=2, shape=[3, 3])  # same as above
    actions, _ = theano.scan(fn=lambda action, p: pm.Categorical('actions', p=p, observed=action),
                             sequences=[actions],
                             non_sequences=[p])
    trace = pm.sample()

The code fails with the following error message:

theano.gof.fg.MissingInputError: Input 0 of the graph (indices start from 0), used to compute Elemwise{Cast{int64}}(<TensorType(int32, vector)>), was not provided and not given a value. Use the Theano flag exception_verbosity='high', for more information on this error.

So maybe it is not possible to use pm.Categorical within theano.scan? Any help as to how to approach this problem would be super helpful!

Upvotes: 0

Views: 739

Answers (1)

Maria
Maria

Reputation: 108

The following solved my problem. I made actions 1-dimensional and p 2-dimensional:

n_trials, n_subj, n_actions = 10, 3, 3

actions = T.as_tensor_variable(np.array([0, 1, 2] * n_trials))  # shape (30, ) instead of (10, 3)
with pm.Model() as model:
    p = pm.Uniform('p', lower=0, upper=1, shape=[n_subj, n_actions])
    indiv = T.tile(T.arange(n_subj), n_trials)
    p = p[indiv]
    actions = pm.Categorical('actions', p=p, observed=actions)
    trace = pm.sample()

Upvotes: 1

Related Questions