Mattijn
Mattijn

Reputation: 13880

Simple subtraction causes a broadcasting issue for different array shapes

I tried solving my issue using this link, describing numpy broadcasting, but to no avail. How to subtract the following numpy arrays:

X = np.array([[[1,2,3,4],[1,2,3,4],[1,2,3,4]],
              [[4,3,2,1],[4,3,2,1],[4,3,2,1]]])
X_mean = np.average(X_, axis=1)

When I do X - X_mean it states:

ValueError: operands could not be broadcast together with shapes (2,3,4) (2,4) 

But doing X[0] - X_mean[0] gives the correct output:

array([[ 0.,  0.,  0.,  0.],
       [ 0.,  0.,  0.,  0.],
       [ 0.,  0.,  0.,  0.]])

Upvotes: 2

Views: 1526

Answers (2)

B. M.
B. M.

Reputation: 18628

As complement : According to Numpy Broadcasting Rules ,

When operating on two arrays, NumPy compares their shapes element-wise. It starts with the trailing dimensions, and works its way forward. Two dimensions are compatible when

  • they are equal
  • one of them is 1

so the best idea is to shape data in a way the mean is made on axis 0.

In your case :

Y=np.rollaxis(X,1) # reshape (3,2,4)

Y-Y.mean(0) is now directly

array([[[ 0.,  0.,  0.,  0.],
        [ 0.,  0.,  0.,  0.]],

       [[ 0.,  0.,  0.,  0.],
        [ 0.,  0.,  0.,  0.]],

       [[ 0.,  0.,  0.,  0.],
        [ 0.,  0.,  0.,  0.]]])

Upvotes: 0

Divakar
Divakar

Reputation: 221564

You need to keep the dimensions aligned for broadcasting to take place. You have -

In [4]: whos
Variable   Type       Data/Info
-------------------------------
X          ndarray    2x3x4: 24 elems, type `int64`, 192 bytes
X_mean     ndarray    2x4: 8 elems, type `float64`, 64 bytes
  1. Axis-0 of X_mean is already aligned with axis-0 of X, so all good there.

  2. Axis-1 of X_mean is to be aligned with axis-2 of X, so put in a new axis for X_mean there with None/np.newaxis so that axis-1 could be pushed back to axis-2.

Let's verify the shape-alignment -

In [7]: X_mean3D = X_mean[:,None,:]

In [8]: whos
Variable   Type       Data/Info
-------------------------------
X          ndarray    2x3x4: 24 elems, type `int64`, 192 bytes
X_mean     ndarray    2x4: 8 elems, type `float64`, 64 bytes
X_mean3D   ndarray    2x1x4: 8 elems, type `float64`, 64 bytes

Then, perform the subtraction that will bring in broadcasting -

In [5]: X - X_mean[:,None,:]
Out[5]: 
array([[[ 0.,  0.,  0.,  0.],
        [ 0.,  0.,  0.,  0.],
        [ 0.,  0.,  0.,  0.]],

       [[ 0.,  0.,  0.,  0.],
        [ 0.,  0.,  0.,  0.],
        [ 0.,  0.,  0.,  0.]]])

Upvotes: 3

Related Questions