Ningza
Ningza

Reputation: 15

How can I create a new dimension when adding/multiplying vectors and matrices? (Python and NumPy)

I would like to compute:

matrix1 + vector * matrix2

where:

In: matrix1.shape
Out: (3, 3)

In: vector.shape
Out: (15,)

In: matrix2.shape
Out: (3, 3)

I did it this way:

answer = []
  for i in vector:
    answer_i = matrix1 + i * matrix2
    answer.append(answer_i)

So, I get a list of len(vector) in which each answer is shape (3,3). I wonder how to do the exact same thing, but without "for" loop and with NumPy arrays. The answer would be an array of shape (3, 3, 15). The answer may be simple but I don't have a lot of experience.

For example:

In: matrix1
Out: array([[1, 2, 3],
            [4, 5, 6],
            [7, 8, 9]])

In: vector
Out: array([-7., -6., -5., -4., -3., -2., -1.,  0.,  1.,  2.,  3.,  4., 5., 6.,  7.])

In: matrix2
Out: array([[ 5,  5,  5],
            [10, 10, 10],
            [20, 20, 20]])

My output (a list of len 15 for now):

[array([[ -34.,  -33.,  -32.],
        [ -66.,  -65.,  -64.],
        [-133., -132., -131.]]),
 array([[ -29.,  -28.,  -27.],
        [ -56.,  -55.,  -54.],
        [-113., -112., -111.]]),
 array([[-24., -23., -22.],
        [-46., -45., -44.],
        [-93., -92., -91.]]),
 array([[-19., -18., -17.],
        [-36., -35., -34.],
        [-73., -72., -71.]]),
 array([[-14., -13., -12.],
        [-26., -25., -24.],
        [-53., -52., -51.]]),
 array([[ -9.,  -8.,  -7.],
        [-16., -15., -14.],
        [-33., -32., -31.]]),
 array([[ -4.,  -3.,  -2.],
        [ -6.,  -5.,  -4.],
        [-13., -12., -11.]]),
 array([[1., 2., 3.],
        [4., 5., 6.],
        [7., 8., 9.]]),
 array([[ 6.,  7.,  8.],
        [14., 15., 16.],
        [27., 28., 29.]]),
 array([[11., 12., 13.],
        [24., 25., 26.],
        [47., 48., 49.]]),
 array([[16., 17., 18.],
        [34., 35., 36.],
        [67., 68., 69.]]),
 array([[21., 22., 23.],
        [44., 45., 46.],
        [87., 88., 89.]]),
 array([[ 26.,  27.,  28.],
        [ 54.,  55.,  56.],
        [107., 108., 109.]]),
 array([[ 31.,  32.,  33.],
        [ 64.,  65.,  66.],
        [127., 128., 129.]]),
 array([[ 36.,  37.,  38.],
        [ 74.,  75.,  76.],
        [147., 148., 149.]])]

I would like the output to be an array of shape (3, 3, 15).

Upvotes: 0

Views: 242

Answers (2)

a_guest
a_guest

Reputation: 36249

You can just insert an extra dimension into the matrices and NumPy broadcasting will do the rest:

matrix1[..., None] + vector*matrix2[..., None]

Upvotes: 1

hpaulj
hpaulj

Reputation: 231395

In [1]: m1 = np.arange(1,10).reshape(3,3)
In [2]: vector = np.array([-7., -6., -5., -4., -3., -2., -1.,  0.,  1.,  2.,  3.
   ...: ,  4., 5., 6.,  7.])
In [4]: m2 = np.array([5,10,20])[:,None]+np.zeros(3,int)
In [5]: m2
Out[5]:
array([[ 5,  5,  5],
       [10, 10, 10],
       [20, 20, 20]])
In [6]: vector.shape
Out[6]: (15,)

np.array(answer) will produce a (15,3,3) array. With numpy broadcasting, we can get the same with:

In [12]: (m1+vector[:,None,None]*m2)
Out[12]:
array([[[ -34.,  -33.,  -32.],
        [ -66.,  -65.,  -64.],
        [-133., -132., -131.]],

       [[ -29.,  -28.,  -27.],
        [ -56.,  -55.,  -54.],
        [-113., -112., -111.]],

       ...

       [[  36.,   37.,   38.],
        [  74.,   75.,   76.],
        [ 147.,  148.,  149.]]])

vector becomes (15,1,1) and the m's (1,3,3) to match, together making (15,3,3).

But if you want the (15,) vector dimension to be last we need to do:

In [13]: (m1[:,:,None]+vector*m2[:,:,None])
Out[13]:
array([[[ -34.,  -29.,  -24.,  -19.,  -14.,   -9.,   -4.,    1.,    6.,
           11.,   16.,   21.,   26.,   31.,   36.],
        [ -33.,  -28.,  -23.,  -18.,  -13.,   -8.,   -3.,    2.,    7.,
           12.,   17.,   22.,   27.,   32.,   37.],
        [ -32.,  -27.,  -22.,  -17.,  -12.,   -7.,   -2.,    3.,    8.,
           13.,   18.,   23.,   28.,   33.,   38.]],
        ...
        [-131., -111.,  -91.,  -71.,  -51.,  -31.,  -11.,    9.,   29.,
           49.,   69.,   89.,  109.,  129.,  149.]]])

Here the broadcasting is (3,3,1) with (15,) => (3,3,15)

We could have also applied a transpose to the first case, changing the (15,3,3) shape to (3,3,15):

(m1+vector[:,None,None]*m2).transpose(1,2,0)

Another way is to join the 15 arrays on a new last axis.

np.stack(answer, axis=2)

Upvotes: 1

Related Questions