NumPy ndarray 内联比较中布尔运算的意外行为

Unexpected behavior of boolean operations in NumPy ndarray inline comparisons

我发现尝试使用 &|==>=numpy ndarray 执行多个布尔比较等经常给出意想不到的结果,表面上似乎违反了纯粹的python操作顺序(我错了;例如,True | False==True 产生 True)。解释这些结果的 "rules" 或幕后发生的事情是什么?这里有几个例子:

  1. 将布尔值 ndarray 与非布尔值 ndarray 元素 比较的结果进行比较:

    In [36]: a = np.array([1,2,3])
    In [37]: b = np.array([False, True, False])
    In [38]: b & a==2 # unexpected, with no error raised!
    Out[38]: array([False, False, False], dtype=bool)
    
    In [39]: b & (a==2) # enclosing in parentheses resolves this
    Out[39]: array([False,  True, False], dtype=bool)
    
  2. 布尔和非布尔 ndarrays 上的元素 &/|

    In [79]: b = np.array([True,False,True])
    
    In [80]: b & a # comparison is made, then array is re-cast into integers!
    Out[80]: array([1, 0, 1])
    
  3. 在两个值内查找数组元素:

    In [47]: a>=2 & a<=2 # have seen this in different stackexchange threads
    ValueError: The truth value of an array with more than one element is ambiguous. Use a.any() or a.all()
    
    In [48]: (a>=2) & a<=2 # similar to behavior in In[38], but instead get *True* boolean array of
    Out[48]: array([ True,  True,  True], dtype=bool)
    
    In [49]: (a>=2) & (a<=2) # expected results
    Out[49]: array([False,  True, False], dtype=bool)
    
  4. 逻辑&/|产生结果不在[0,1]中(如果布尔值结果被强制返回 int).

    In [90]: a & 2
    Out[90]: array([0, 2, 2])
    

我欢迎更多这种行为的例子。

我认为您对 & | 二元运算符与比较运算符的优先级感到困惑:

>>> import dis
>>> dis.dis("b & a==2")
  1           0 LOAD_NAME                0 (b)
              2 LOAD_NAME                1 (a)
              4 BINARY_AND
              6 LOAD_CONST               0 (2)
              8 COMPARE_OP               2 (==)
             10 RETURN_VALUE

你可以在这里看到 BINARY_AND 首先完成(在 ba 之间)然后将结果与 2 进行比较,因为它是一个布尔值数组,全是False

&| 具有较低优先级的原因是因为它们不是逻辑运算符,它代表 numpy 恰好用于逻辑的二进制(数学?)运算,例如对于整数,我肯定希望 & 首先发生:

if 13 & 7 == 5:

不幸的是,numpy 不能覆盖逻辑 andor 运算符的行为,因为它们的优先级作为逻辑运算符是有意义的,但不幸的是,它们不能被覆盖,所以我们只需要生活意志在做布尔数组时添加很多括号。

请注意,有一个 proposal to allow and or to be overloaded but was not passed,因为基本上它对 numpy 来说只是一个很小的便利,同时会使所有其他严格的布尔运算变慢。

a>=2 & a<=2 被评估为 a>=(2 & a)<=2

() 部分的计算结果为 array([0, 0, 2], dtype=int32)

a>=(2 & a) 是一个布尔数组。但它是 Python a<x<b 表达式的一部分,它在内部使用短路。也就是说,它评估 a<x 并根据其值实际上可能会跳过 <b 部分。类似于 True if a<x else x<b.

熟悉的 ValueError ambiguous 出现在标量 Python 布尔上下文中使用布尔数组时。