为什么没有链接(间隔)比较在numpy数组上工作?

时间:2017-02-20 22:39:00

标签: python-2.7 numpy

a < b < c是Python中的chained expression,看起来它适用于定义了适当比较运算符的对象,但它不适用于numpy数组。为什么呢?

import numpy as np

class ContrarianContainer(object):
    def __init__(self, x):
        self.x = x
    def __le__(self, y):
        return not self.x <= y
    def __lt__(self, y):
        return not self.x < y
    def __ge__(self, y):
        return not self.x >= y
    def __gt__(self, y):
        return not self.x > y
    def __eq__(self, y):
        return not self.x == y
    def __ne__(self, y):
        return not self.x != y

numlist = np.array([1,2,3,4])
for n in numlist:
    print 0 < n < 3.5
for n in numlist:
    print 0 > ContrarianContainer(n) > 3.5
print 0 < numlist < 3.5

打印:

True
True
True
False
True
True
True
False
---------------------------------------------------------------------------
ValueError                                Traceback (most recent call last)
<ipython-input-187-277da7750148> in <module>()
      4 for n in numlist:
      5     print 0 < n < 3.5
----> 6 print 0 < numlist < 3.5

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

2 个答案:

答案 0 :(得分:6)

0 < numlist < 3.5

相当于:

(0 < numlist) and (numlist < 3.5)

除了numlist仅评估一次。

两个结果之间的隐式and导致错误

答案 1 :(得分:3)

所以文档说:

  

形式上,如果a,b,c,...,y,z是表达式而op1,op2,...,opN是比较运算符,那么op1 b op2 c ... y opN z相当于a op1 b和b op2 c和... y opN z,除了每个表达式最多被评估一次。

  

(但在两种情况下,当发现x&lt; y为假时,根本不评估z。)

标量

In [20]: x=5
In [21]: 0<x<10
Out[21]: True
In [22]: 0<x and x<10
Out[22]: True

但是有一个数组

In [24]: x=np.array([4,5,6])    
In [25]: 0<x and x<10
...
ValueError: The truth value of an array with more than one element is ambiguous. Use a.any() or a.all()

当在需要标量布尔值的上下文中使用numpy boolean时,会出现此ValueError。

In [26]: (0<x)
Out[26]: array([ True,  True,  True], dtype=bool)

In [30]: np.array([True, False]) or True
...
ValueError: The truth value of an array with more than one element is ambiguous. Use a.any() or a.all()
In [33]: if np.array([True, False]): print('yes')
ValueError: The truth value of an array with more than one element is ambiguous. Use a.any() or a.all()

它评估0<x,但甚至不评估x<10,因为它不能在or/and上下文中使用生成的布尔数组。 numpy已定义|&,但未定义orand

In [34]: (0<x) & x<10
Out[34]: array([ True,  True,  True], dtype=bool)

当我们使用0 < x <10时,我们隐含地期望评估标量链式表达式的矢量化版本。

In [35]: f = np.vectorize(lambda x: 0<x<10, otypes=[bool])
In [36]: f(x)
Out[36]: array([ True,  True,  True], dtype=bool)
In [37]: f([-1,5,11])
Out[37]: array([False,  True, False], dtype=bool)

请注意,尝试将链接应用于列表甚至不会超过第一个<

In [39]: 0 < [-1,5,11]
TypeError: unorderable types: int() < list()

这组表达式表明&运算符优先于<运算符:

In [44]: 0 < x & x<10
ValueError ...

In [45]: (0 < x) & x<10
Out[45]: array([ True,  True,  True], dtype=bool)

In [46]: 0 < x & (x<10)
Out[46]: array([False,  True, False], dtype=bool)

In [47]: 0 < (x & x)<10
ValueError...

所以安全版本为(0 < x) & (x<10),确保在<之前评估所有&