0

This is question is not a duplicate of another question. The other question asks about a single boolean output (True/False) when a conditional statement is applied on a numpy array. That's why it is important to use np.any() or np.all() to determine the output unambiguously.

My question here talks about creating an element-wise array-output of boolean True/False values, when we evaluate if an array a is between 2 and 5 using an expression 2 < a < 5. This question delves into the viability of such a convenience expression while using numpy arrays.

Python allows the following for a scalar.

a = 7
print(2 < a < 5) # False
a = 4
print(2 < a < 5) # True

However, if I try the same with a numpy array it does not work.

import numpy as np

a = np.arange(10)
2 < a < 5

This gives an error. But, any of the following two methods works (as expected):

np.logical_and(2 < a, a < 5) # method-1

(2 < a) & (a < 5) # method-2

Output:

array([False, False, False,  True,  True, False, False, False, False,
       False])

So, my question is: is there any numpy equivalent such that you could just write 2 < a < 5 and get the above output?

Community
  • 1
  • 1
CypherX
  • 7,019
  • 3
  • 25
  • 37
  • 4
    No, that logical an is the correct way. Note the use of () to control operator prescedence. You can't do that with the `a – hpaulj Nov 06 '19 at 22:35
  • Python comparator chaining requires that the comparator strictly return a boolean---with numpy, this behavior is overridden so that a comparator returns a numpy array instead, so comparator chaining will not work. Relevant python docs here: https://docs.python.org/3/reference/expressions.html#comparisons – alkasm Nov 07 '19 at 00:00
  • Does this answer your question? [ValueError: The truth value of an array with more than one element is ambiguous. Use a.any() or a.all()](https://stackoverflow.com/questions/10062954/valueerror-the-truth-value-of-an-array-with-more-than-one-element-is-ambiguous) --- in particular [this answer](https://stackoverflow.com/a/44345755/5087436) gives a nice explanation. – alkasm Nov 07 '19 at 00:04
  • @alkasm The link you shared was helpful to look at and understand the content shared in the question there. However, it does not let me produce the output I showed above. I understand that this probably is not how `numpy` is designed to work. And so will keep using `np.logical_and` or `&`. This did not stop me from my work. However, I thought it's an interesting thought and may be someone could shed some light on it. – CypherX Nov 07 '19 at 00:59
  • @alkasm Thank you for sharing the links. The [answer](https://stackoverflow.com/a/44345755/5087436) somewhat sheds some light in this area. But it only makes me wonder: _could this (`2 < a < 5`) be a possible feature in `numpy` in future?_ – CypherX Nov 07 '19 at 01:19
  • @hpaulj Thank you for your comment. Yes, it makes sense to not fight it and adapt to the design of `numpy` to do what we need to. However, what do you think about the possibility of this being a _feature in `numpy`_? – CypherX Nov 07 '19 at 01:21
  • There is no specialized vectorized shortcut in NumPy. You need to create two boolean masks and find their intersection: `(2 < a) & (a < 5)` – Matt Eding Nov 07 '19 at 06:21
  • @MattEding Thank you. I know; I have already mentioned it in the question. – CypherX Nov 07 '19 at 06:49

1 Answers1

2

What about this?

import numpy as np
a = np.arange(10)

bools = map(lambda x: 2 < x < 5, a)
bools = np.fromiter(bools, bool)

suba = a[bools]
Toothpick Anemone
  • 4,290
  • 2
  • 20
  • 42
  • Thank you for your answer. It shows one way of approaching the problem. And so I would upvote it. However, I was looking for a single line vectorized numpy equivalent of `2 < a < 5`. – CypherX Nov 07 '19 at 01:32
  • 2
    The `fromiter` is much, much slower than using `&`. I really advise __not__ doing the above approach. – Matt Eding Nov 07 '19 at 06:25