12
votes

In Numpy, I can generate a boolean array like this:

>>> arr = np.array([1, 2, 1, 2, 3, 6, 9])
>>> arr > 2
array([False, False, False, False,  True,  True,  True], dtype=bool)

Is is possible to chain comparisons together? For example:

>>> 6 > arr > 2
array([False, False, False, False,  True,  False,  False], dtype=bool)
3
FYI, PEP 535 proposes to make this possible in python 3.7. - drammock

3 Answers

24
votes

AFAIK the closest you can get is to use &, |, and ^:

>>> arr = np.array([1, 2, 1, 2, 3, 6, 9])
>>> (2 < arr) & (arr < 6)
array([False, False, False, False,  True, False, False], dtype=bool)
>>> (2 < arr) | (arr < 6)
array([ True,  True,  True,  True,  True,  True,  True], dtype=bool)
>>> (2 < arr) ^ (arr < 6)
array([ True,  True,  True,  True, False,  True,  True], dtype=bool)

I don't think you'll be able to get a < b < c-style chaining to work.

10
votes

You can use the numpy logical operators to do something similar.

>>> arr = np.array([1, 2, 1, 2, 3, 6, 9])
>>> arr > 2
array([False, False, False, False,  True,  True,  True], dtype=bool)
>>>np.logical_and(arr>2,arr<6)
Out[5]: array([False, False, False, False,  True, False, False], dtype=bool)
2
votes

Chained comparisons are not allowed in numpy. You need to write both left and right comparisons separately, and chain them with bitwise operators. Also you'll need to parenthesise both expressions due to operator precendence (|, & and ^ have a higher precedence). In this case, since you want both conditions to be satisfied you need an bitwise AND (&):

(2<arr) & (arr<6)
# array([False, False, False, False,  True, False, False])

It was actually proposed to make this possible in PEP 535, though it still remains deferred. In it there is an explanation on why this occurs. As posed in the question, chaining comparisons in such way, yields:

2<arr<6

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

The problem here, is that python is internally expanding the above to:

2<arr and arr<6

Which is what causes the error, since and is implicitly calling bool, and NumPy only permits implicit coercion to a boolean value for single elements (not arrays with size>1), since a boolean array with many values does not evaluate neither to True or False. It is due to this ambiguity that this isn't allowed, and evaluating an array in boolean context always yields a ValueError