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

Welcome to Programming Tutorial official website. Today - we are going to cover how to solve / find the solution of this error How can I create a new dimension when adding/multiplying vectors and matrices? (Python and NumPy) on this date .

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).

Answer

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)