I still wasn’t able to figure out how to use patsy’s dmatrices, no clue.
In the case of a model that isn’t using intercepts and slopes, but trying to model the differences in standard deviations directly in the way that was initially posted by @junpenglao, how do I merge the different priors, so I can use it with the observed variable? To be clear: there are several variables that define sigma for the different conditions/blocks/directions, but I have only 1 observed variable with only 1 sigma argument. How do I map the different sigma variables to their respective measurements?!
I’ve been trying to get this information for weeks now, and it doesn’t seem to be clearly explained anywhere? It’s not obvious to me. dims, coords and how indexing works aren’t well documented.
With the mock-up data in the gist of my previous post, how would I provide these different mu distributions as one to the observed variable?
For a variable that is dummy coded with 0 and 1, like direction in my case, I tried it this way:
with pm.Model(coords=coords) as proj_model:
direction_idx = pm.Data('direction_idx', direction_indices, dims='obs_id')
user_idx = pm.Data('user_idx', user_indices, dims='obs_id')
# Hyperpriors:
global_ortho = pm.Gamma('ortho_global', mu=3, sigma=10)
global_ortho_sd = pm.HalfCauchy('ortho_global_sd', 5)
global_diff = pm.Gamma('diff_global', mu=3, sigma=3)
global_diff_sd = pm.HalfCauchy('diff_global_sd', 5)
global_parallel = pm.Deterministic('parallel_global', global_ortho+global_diff)
# Priors
ortho_user = pm.Gamma('ortho_user', mu=global_ortho, sigma=global_ortho_sd, dims='User')
diff_user = pm.Gamma('diff_user', mu=global_diff, sigma=global_diff_sd, dims='User')
parallel_user = pm.Deterministic('parallel_user', ortho_user+diff_user)
# Expected deviation per user:
theta = ortho_user[user_idx] * (1-direction_idx) + parallel_user[user_idx] * direction_idx
projection = pm.Normal('projection', 0.0, sigma=theta, observed=df['projection'], dims='obs_id')
Due to the multiplication with either 0 or 1, rows that have direction==0
(orthogonal), use the ortho_user variable as prior, and rows with direction==1
use the parallel_user variable.
But for a variable like block that goes from 0 to 2, I can’t simply multiply with the dummy coded variable, as it would multiply by 2. I tried to work around it this way:
with pm.Model(coords=coords) as block2_model:
user_idx = pm.Data('user_idx', user_indices, dims='obs_id')
block_idx = pm.Data('block_idx', block_indices, dims='obs_id')
#block_id_idx = pm.Data('block_id_idx', block_id_indices, dims='obs_id')
# Hyperpriors:
global_blocks13 = pm.Gamma('blocks13_global', mu=5, sigma=10)
global_blocks13_sd = pm.HalfCauchy('blocks13_global_sd', 5)
global_diff = pm.Gamma('diff_global', mu=5, sigma=3)
global_diff_sd = pm.HalfCauchy('diff_global_sd', 5)
global_block2 = pm.Deterministic('block2_global', global_blocks13+global_diff)
# Priors
blocks13_user = pm.Gamma('blocks13_user', mu=global_blocks13, sigma=global_blocks13_sd, dims='User')
diff_block2 = pm.Gamma('diff_block2', mu=global_diff, sigma=global_diff_sd, dims='User')
block2_user = pm.Deterministic('block2_user', blocks13_user+diff_block2)
# Expected deviation per user:
theta = blocks13_user[user_idx] * (block_idx.eval() != 1) + block2_user[user_idx] * (block_idx.eval() == 1)
projection = pm.Normal('projection', 0.0, sigma=theta, observed=df['projection'], dims='obs_id')
But, honestly, using eval()
to get the values doesn’t seem like the appropriate way to do it?
And when I need to get more complex with interactions between blocks and direction, this will get very complicated. I guess, this is where the DesignMatrix should come in handy? But I don’t know where to put it and what to do with it.
It’s a lot of puzzle pieces that I don’t know how to fit together.