为什么链式(间隔)比较不适用于 numpy 数组? [英] Why doesn't chained (interval) comparison work on numpy arrays?

查看:28
本文介绍了为什么链式(间隔)比较不适用于 numpy 数组?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

a <<c 是 Python 中的链式表达式,它看起来就像它适用于定义了适当的比较运算符的对象,但它不适用于 numpy 数组.为什么?

a < b < c is an chained expression in Python, and it looks like it works on objects with appropriate comparison operators defined, but it doesn't work on numpy arrays. Why?

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

推荐答案

所以文档说:

形式上,如果 a, b, c, ..., y, z 是表达式并且 op1, op2, ..., opN 是比较运算符,那么 a op1 b op2 c ... y opN z 等价于a op1 b 和 b op2 c 和 ... y opN z,除了每个表达式最多计算一次.

Formally, if a, b, c, ..., y, z are expressions and op1, op2, ..., opN are comparison operators, then a op1 b op2 c ... y opN z is equivalent to a op1 b and b op2 c and ... y opN z, except that each expression is evaluated at most once.

(但在这两种情况下,当发现 x

(but in both cases z is not evaluated at all when x < y is found to be false).

对于标量

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 布尔值时,会出现此 ValueError.

This ValueError arises when a numpy boolean is used in a context that expects a scalar boolean.

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,因为它不能在 0<x 中使用结果布尔数组代码>或/和上下文.numpy 已经定义了 |&,但没有定义 orand.

It evaluates the 0<x, but doesn't even get to evaluating the x<10, because it can't use the resulting boolean array in a or/and context. numpy has defined | and &, but not or or and.

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

当我们使用 0 <x <10 我们隐含地期望计算标量链式表达式的矢量化版本.

When we use 0 < x <10 we are implicitly expecting to evaluate a vectorized version of the scalar chained expression.

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)

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

Note that attempting to apply chaining to a list doesn't even get past the first <:

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


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


This set of expressions indicates that the & operator has precedence over the < operator:

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 ,确保在 & 之前评估所有 <.

So the safe version is (0 < x) & (x<10), making sure that all < are evaluated before the &.

下面是一个进一步的例子,证实了捷径求值:

Here's a further example that confirms the short-cut and evaluation:

In [53]: x=2
In [54]: 3<x<np.arange(4)
Out[54]: False
In [55]: 1<x<np.arange(4)
Out[55]: array([False, False, False,  True])

3<xFalse 时,它会返回该值,无需进一步评估.

When 3<x is False, it returns that, without further evaluation.

当它为 True 时,它继续计算 x,返回一个 4 元素的布尔值.

When it is True, it goes on to evaluate x<np.arange(4), returning a 4 element boolean.

或者使用一个根本不支持 < 的列表:

Or with a list that doesn't support < at all:

In [56]: 3<x<[1,2,3]
Out[56]: False
In [57]: 1<x<[1,2,3]
Traceback (most recent call last):
  File "<ipython-input-57-e7430e03ad55>", line 1, in <module>
    1<x<[1,2,3]
TypeError: '<' not supported between instances of 'int' and 'list'

这篇关于为什么链式(间隔)比较不适用于 numpy 数组?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆