Pymc3 vector concatenation

Hi. Is there a way to group various subsets of random variables into a single vector to use in vector operations? For example, say my model looks something like:

a = pm.Normal(…, shape=4)
b = pm.Normal(…, shape=7)

and I would like to compute something like the dot product of [ a[2], b[1], b[2], b[3], b[4] ] with a 5-element vector x = [x1, x2, x3, x4, x5]. How would I go about doing that?

I have tried doing approximately these two solutions:

vec = pm.math.concatenate( (a[2], b[1:5] )
vec = pm.math.stack( (a[2], b[1:5] )

but I get errors about joining Tensors of different dimensions.

I think I am missing something very simple here, anybody know what it is?

Thanks.

try using

import theano.tensor as tt
tt.printing.Print('a')(a.shape)

to find out the shape of a[2] and b[1:5].

Also, your sub-vectors are probably 1-dimensional. Try to use the axis keyword to explicitly state in which direction to join them, as in

pm.math.stack( [ a[2], b[1:5] ] , axis = 0)

(sorry that i cannot test/confirm that atm)

So when I try printing the various shapes, I get that the shape of a[2] is [] and the shape of b[1:5] is [4]. For reference, the shape of a is [4] and the shape of b is [7]. It looks like this is just returning the value of the shape parameter in the respective pm.Normal call.

Your suggestion to specify the axis resulted in the error “TypeError: Join() can only join tensors with the same number of dimensions.” for axis = 0, and “IndexError: axis 1 is out of bounds [-1, 1)” for axis = 1.

I tried one more thing. I guessed that this might be happening because a[2] is a scalar and b[1:5] is a vector, so I attempted pm.math.stack( [ a[2:4], b[1:5] ] , axis = 0). This yielded the error “ValueError: all the input array dimensions except for the concatenation axis must match exactly”.

When you index one element from a the result is a scalar, thus the shape error when you are trying to concatenate it with a 1d tensor. You can expand the dimension, or create 2d RVs like

a = pm.Normal(…, shape=(4, 1))
b = pm.Normal(…, shape=(7, 1))

This was helpful. I managed to get it working by doing

a = pm.Normal(..., shape=(4,1))
b = pm.Normal(..., shape=(7,1))

vec = pm.math.concatenate( (a[2:3], b[1:5]), axis=0)

Printing the shapes showed that a[2] does not have the same shape as a[2:3].

Thanks very much for your assistance!

2 Likes

This answer works great, but is there a way to assign vec to its own pymc3 variable in the model, and ignore a and b? I do not need a and b as standalone parameters in the trace, but would like to use vec__0, …, vec__n, instead. That way, I can work with a variable number of terms in an N-d linear model where I want different priors for different terms.

You should be able to wrap it in pm.Deterministic:

vec = pm.Deterministic('vec', pm.math.concatenate( (a[2:3], b[1:5]), axis=0))