NumPy链式比较与两个谓词

14
在NumPy中,我可以像这样生成一个布尔数组:
>>> arr = np.array([1, 2, 1, 2, 3, 6, 9])
>>> arr > 2
array([False, False, False, False,  True,  True,  True], dtype=bool)

我们如何将比较链接在一起?例如:

>>> 6 > arr > 2
array([False, False, False, False,  True,  False,  False], dtype=bool)

试图这样做会导致错误消息

ValueError:具有多个元素的数组的真值是模棱两可的。使用 a.any() 或 a.all()


1
FYI,PEP 535 建议在 Python 3.7 中实现此功能。 - drammock
1
PEP 535在2023年仍然处于推迟状态 :| - Mattwmaster58
3个回答

27

据我所知,你能够使用&|^来获得最接近的效果:

>>> 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)
我不认为你能让 a < b < c 这样的链接方式起作用。

11

您可以使用NumPy逻辑运算符进行类似的操作。

>>> 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)

相当于 &,我更喜欢这种写法。 - Mattwmaster58

4
numpy中不允许链接比较。您需要分别编写左侧和右侧比较,并使用位运算符chain它们。此外,由于运算符优先级|&^具有更高的优先级),您需要将两个表达式括起来。在这种情况下,因为您希望同时满足两个条件,所以需要一个按位与(&)。
(2<arr) & (arr<6)
# array([False, False, False, False,  True, False, False])

实际上在PEP 535中提出了这个可能性,但它仍然被推迟。其中有一个关于为什么会发生这种情况的解释。就像问题中提出的那样,以这种方式链接比较会产生以下结果:

2<arr<6

价值错误:具有多个元素的数组的真实价值是模棱两可的。 使用 a.any() 或 a.all()。
问题在于,Python 在内部将上述内容扩展为:
2<arr and arr<6

这就是导致错误的原因,因为and隐式调用了bool,而NumPy仅允许对单个元素进行布尔值的隐式转换(不适用于size>1的数组),因为具有多个值的布尔数组既不等于True也不等于False。正是由于这种不确定性,所以不允许这样做,在布尔上下文中评估数组总是产生ValueError

1
谢谢您提供这个更新的答案!我希望这个提案能够被接受。 - evn

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接