Search code examples
pythonnumpylinear-algebrabroadcasting

Summing over 2D and 3D arrays using broadcasting


Consider the following MWE:

import numpy as np
n=2
N = 6
a = np.random.randint(0,10,size=(N,1))
b = np.random.randint(0,10,size=(N,n))
c = np.random.randint(0,10,size=(n,N,5))

where c is e.g. (it is random recall):

array([[[7 5 1 7 0]
  [2 8 2 1 4]
  [0 4 1 7 3]
  [1 6 6 9 6]
  [9 6 0 0 2]
  [9 6 0 6 7]]

 [[0 3 9 0 3]
  [4 7 5 3 8]
  [8 0 6 7 9]
  [5 4 9 5 2]
  [5 6 6 8 7]
  [7 7 2 6 0]]])

and has shape (2,6,5).

From which we make:

out = a+b
>>>out
array([[ 9,  7],
       [ 5,  7],
       [ 7,  3],
       [ 9,  9],
       [15, 10],
       [ 8,  9]])

which has shape (6,2).

Now here is what I want to do: I want to add the first column of out to the first matrix of c (i.e. where matrices are indexed by the first dimension of c), the second column of out to the second column of c and so on (you get the drift). Currently, I am attempting to do this using broadcasting but I seem to have confused myself.

I want to do without using loops as my real problem is very large.

Desired output:

>>>np.stack([out[:,i][:,np.newaxis] + c[i] for i in range(2)])

array([[[16, 14, 10, 16,  9],
        [ 7, 13,  7,  6,  9],
        [ 7, 11,  8, 14, 10],
        [10, 15, 15, 18, 15],
        [24, 21, 15, 15, 17],
        [17, 14,  8, 14, 15]],

       [[ 7, 10, 16,  7, 10],
        [11, 14, 12, 10, 15],
        [11,  3,  9, 10, 12],
        [14, 13, 18, 14, 11],
        [15, 16, 16, 18, 17],
        [16, 16, 11, 15,  9]]])

which has shape (2,6,5).

Attempt:

out[None, :,:] + c

which renders the following error:

---------------------------------------------------------------------------
ValueError                                Traceback (most recent call last)
<ipython-input-702-d54cfe51ec32> in <module>
----> 1 out[None, :,:] + c

ValueError: operands could not be broadcast together with shapes (1,6,2) (2,6,5)

Help would be most appreciated.


Solution

  • You can transpose and add a dimension and let the broadcasting do the job:

    out.T[...,None]+c 
    

    Explanation: .T transposes out (to shape (2,6)) and [...,None] adds an extra dimension as the latest dimension of out (Now out is of shape (2,6,1)). Finally, the broadcasting to c with shape (2,6,5) will broadcast all elements to the depths of c as desired.