Julien
Julien

Reputation: 137

How to create prior variables from a dictionary?

I have a large number of priors that can be put into a dictionary. For the sake of simplicity, let's use the following example containing only 3 priors:

d = {'a1':{'name':'a1','lower':0,'upper':10},\
'a2':{'name':'a2','lower':0,'upper':10},\
'a3':{'name':'a3','lower':0,'upper':10}}

I can create these variables manually with:

import pymc3
model = pymc3.Model()
with model:
    a1 = pymc3.Uniform('a1',lower=0,upper=10)
    a2 = pymc3.Uniform('a2',lower=0,upper=10)
    a3 = pymc3.Uniform('a3',lower=0,upper=10)

But the number of priors that I have makes this approach painful. Is there a proper way to define the priors from a dictionary in pymc3? So far, the only automatic solution that I've found is:

list_prior_names = ['a1','a2','a3']
for prior_name in list_prior_names:
    exec(prior_name+"=pymc3.Uniform(prior_name,lower=d[prior_name]['lower'],upper=d[prior_name]['upper'])")

Is there a better way to proceed?

Similarly, I have a dictionary that gives the relations between these priors and other variables. For the sake of simplicity, let's use the following example defining linear relations between the priors and these new variables:

relations = {'a1':{'b1':2,'b2:4},'a2':{'b1':1},'a3':{'b3':5}}

Once again, I could create b1, b2 and b3 manually with the following code:

b1 = 2*a1 + a2
b2 = 4*a1
b3 = 5*a3

I could use a solution similar to the other one, but I think that there is here too a better way to create b1, b2, b3.

The code I'm currently using is:

import pymc3
model = pymc3.Model()

obs1,obs2,obs3 = 2,4,5

d = {'a1':{'name':'a1','lower':0,'upper':10},\
'a2':{'name':'a2','lower':0,'upper':10},\
'a3':{'name':'a3','lower':0,'upper':10}}

with model:
    list_prior_names = ['a1','a2','a3']
    for prior_name in list_prior_names:
        exec(prior_name+"=pymc3.Uniform(prior_name,lower=d[prior_name]['lower'],upper=d[prior_name]['upper'])")

    b1 = 2*a1 + a2
    b2 = 4*a1
    b3 = 5*a3

    m1 = pymc3.Normal('M1',mu=b1,sd=0.1,observed=obs1)
    m2 = pymc3.Normal('M2',mu=b2,sd=0.1,observed=obs2)
    m3 = pymc3.Normal('M3',mu=b3,sd=0.1,observed=obs3)

    trace = pymc3.sample(1000)

If anyone had a clue on a proper way to create a1, a2, a3, b1, b2 and b3, I'd be grateful.

Upvotes: 1

Views: 180

Answers (1)

Julien
Julien

Reputation: 137

In fact, pymc3 can make its calculations with variables that are defined in dictionaries. I've therefore written the following code to solve my problem. I give it here, in case someone has some day to deal with the same question.

import pymc3
model = pymc3.Model()

obs1,obs2,obs3 = 2,4,5

d = {'a1':{'name':'a1','lower':0,'upper':10},
     'a2':{'name':'a2','lower':0,'upper':10},
     'a3':{'name':'a3','lower':0,'upper':10}}

relations = {'b1':{'a1':2,'a2':1},'b2':{'a1':4},'b3':{'a3':5}}

correspondances_dict = {'b1':{'random_var_name':'m1','observation':obs1},
                        'b2':{'random_var_name':'m2','observation':obs2},
                        'b3':{'random_var_name':'m3','observation':obs3}}

with model:
    priors={prior_name:pymc3.Uniform(prior_name,lower=d[prior_name]['lower'],
            upper=d[prior_name]['upper']) for prior_name in list(d.keys())}

    intermediate_vars = {intermediate_var:sum([relations[intermediate_var][prior_name]*priors[prior_name]
        for prior_name in list(relations[intermediate_var].keys())])
        for intermediate_var in list(relations.keys())}

    observed_vars = {correspondances_dict[intermediate_var]['random_var_name']:
                    pymc3.Normal(correspondances_dict[intermediate_var]['random_var_name'],
                                 mu=intermediate_vars[intermediate_var],
                                 sd=0.1,
                                 observed=correspondances_dict[intermediate_var]['observation'])
                    for intermediate_var in list(intermediate_vars.keys())}

    trace = pymc3.sample(1000)

Upvotes: 1

Related Questions