phoenix bai
phoenix bai

Reputation: 73

numpy array subtraction, how come?

Cannot quite understand why x-y is a matrix?

and what is the difference between the shape of x (4,) and y (4,1), aren't they all treated as vectors?

>>> x = np.array([1,2,3,4])
>>> y = x[:,None]
>>> x.shape
(4,)
>>> y.shape
(4, 1)
>>> x
array([1, 2, 3, 4])
>>> y
array([[1],
       [2],
       [3],
       [4]])
>>> x-y
array([[ 0,  1,  2,  3],
       [-1,  0,  1,  2],
       [-2, -1,  0,  1],
       [-3, -2, -1,  0]])

Upvotes: 4

Views: 1976

Answers (2)

Darshan Chaudhary
Darshan Chaudhary

Reputation: 2233

what is the difference between the shape of x (4,) and y (4,1)

x is a vector ; you would need 1 index to access it's elements.

y is a 2-D array ; you would need 2 indexes to access it's elements.

Cannot quite understand why x-y is a matrix?

This is because x and y get broadcasted when you subtract them.

x - y becomes :

[1 2 3 4          [1 1 1 1

 1 2 3 4           2 2 2 2
            -     
 1 2 3 4           3 3 3 3

 1 2 3 4]          4 4 4 4]

Upvotes: 2

Anand S Kumar
Anand S Kumar

Reputation: 90999

This is explained well in the documentation for numpy broadcasting -

General 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

  1. they are equal, or
  2. one of them is 1

If these conditions are not met, a ValueError: frames are not aligned exception is thrown, indicating that the arrays have incompatible shapes. The size of the resulting array is the maximum size along each dimension of the input arrays.

Arrays do not need to have the same number of dimensions. For example, if you have a 256x256x3 array of RGB values, and you want to scale each color in the image by a different value, you can multiply the image by a one-dimensional array with 3 values. Lining up the sizes of the trailing axes of these arrays according to the broadcast rules,

(Emphasis mine)

When operating array of shape (4,) with array of shape (4,1) , the first one is broadcasted to (1,4) (As it starts at the trailing dimension and works its way forward, replacing them by 1 if no value at that dimension, hence (4,) becomes (1,4) .) and then operating both of them together create an array of shape (4,4) .

And the shape (4,1) is not treated as vector. It is a 2-D array.

Same would have occured if x was array([[1, 2, 3, 4]]) , an array of shape (1,4) -

Example -

In [70]: y
Out[70]:
array([[1],
       [2],
       [3],
       [4]])

In [71]: x = np.array([x])

In [72]: x
Out[72]: array([[1, 2, 3, 4]])

In [73]: x - y
Out[73]:
array([[ 0,  1,  2,  3],
       [-1,  0,  1,  2],
       [-2, -1,  0,  1],
       [-3, -2, -1,  0]])

Broadcasting always matches starting at the last dimensions, hence trying something like below throws an error -

In [79]: y = np.array([[1,2,3,4],[5,6,7,8]])

In [80]: y.shape
Out[80]: (2, 4)

In [81]: x = np.array([1,2])

In [82]: x.shape
Out[82]: (2,)

In [83]: y - x
---------------------------------------------------------------------------
ValueError                                Traceback (most recent call last)
<ipython-input-83-4abb3bd0a148> in <module>()
----> 1 y - x

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

This is because first it checks the last dimensions of both arrays, one is 4 and the other is 2, they don't match according to the rules, hence it throws the error. If the shape of x was (2,1) , it would have worked. Example -

In [84]: y - x.reshape((2,1))
Out[84]:
array([[0, 1, 2, 3],
       [3, 4, 5, 6]])

Upvotes: 4

Related Questions