andrew
andrew

Reputation: 1843

unexpected result when comparing numpy arrays with different shapes

When comparing 2 numpy arrays of different sizes I would expect either a boolean array based on broadcasting or an error to be raised. Sometimes I just get False, as if its comparing them as objects.

In the following I would expect that if - fails, so does ==:

In [18]: a = np.zeros((2,7,5))

In [19]: b = np.zeros((2,7))

In [20]: a == b
Out[20]: False

In [21]: a - b
---------------------------------------------------------------------------
ValueError                                Traceback (most recent call last)
<ipython-input-21-a5f966a4b1f4> in <module>()
----> 1 a - b

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

Upvotes: 2

Views: 662

Answers (2)

Kasravnd
Kasravnd

Reputation: 107287

Arithmetic operators on arrays apply elementwise. A new array is created and filled with the result, and if the arrays do not have same shapes python will raise a ValueError to notify you about the problem,as its an Arithmetic Error.

But for == python returns a bool value and its possible that you want to compare 2 arrays together and get a bool value (even if they have not a same shape),so first it checks for the shapes of arrays; if those are not same it returns False.

Upvotes: 1

hpaulj
hpaulj

Reputation: 231395

The a-b fails because automatic broadcasting occurs on the left, not the right.

np.zeros((2,7,5))-np.zeros((2,7))[:,:,None]

works

np.zeros((2,7,5))==np.zeros((2,7))[:,:,None]

and the equality test works element by element.

But as Kasra notes, in a==b, the element by element comparison will fail. Clearly the two arrays are not equal. Returning False is consistent with other Python uses of == (.__eq__ method). I don't know if the numpy developers even considered the alternative of returning a ValueError.

Consider what Python returns when comparing strings and lists:

'two'=='three'
[1,2,3]==[1]
'string'==['l','i','s','t']

I can't think of a case where __eq__ returns an error instead of False. But you might be able to code your own class that way.

Python documentation for __eq__ says:

A rich comparison method may return the singleton NotImplemented if it does not implement the operation for a given pair of arguments. By convention, False and True are returned for a successful comparison. However, these methods can return any value, so if the comparison operator is used in a Boolean context (e.g., in the condition of an if statement), Python will call bool() on the value to determine if the result is true or false.

numpy follows this - returning a boolean array if possible, False otherwise.

bool(np.zeros((2,7,5))==np.zeros((2,7))[:,:,None])

produces an error message:

ValueError: The truth value of an array with more than one element is ambiguous. Use a.any() or a.all()

which is the root of a frequent SO question.

Upvotes: 1

Related Questions