假设有一个NumPy数组 x
。下面这段代码:
(x > 1) and (x < 3)
出现以下错误:
ValueError: 数组中有多个元素的真值不明确。请使用 a.any() 或 a.all()
该如何修复?
假设有一个NumPy数组 x
。下面这段代码:
(x > 1) and (x < 3)
出现以下错误:
ValueError: 数组中有多个元素的真值不明确。请使用 a.any() 或 a.all()
该如何修复?
a
和 b
是布尔类型的 NumPy 数组,那么 &
操作会返回它们对应元素的逐个与操作结果:a & b
这会返回一个布尔型数组。要将其缩减为单个的布尔值,可以使用以下方法之一
(a & b).any()
或者(a & b).all()
注意:如果a
和b
是非布尔数组,请考虑改用(a - b).any()
或(a - b).all()
。
Numpy 的开发者们认为,在布尔上下文中评估数组没有一个公认的方式:它可以表示只要有一个元素为True
就返回True
,也可以表示只有所有元素都为True
才返回True
;或者仅在数组长度非零时返回True
,这只是其中的三种可能性。
由于不同的用户可能会有不同的需求和假设,Numpy 开发者拒绝猜测,并决定在尝试在布尔上下文中评估数组时引发ValueError
异常。将and
应用于两个 Numpy 数组会导致这两个数组在布尔上下文中被评估(通过在 Python 3 中调用__bool__
或在 Python 2 中调用__nonzero__
)。
np.all
和np.any
能够短路,但是传递给它的参数在np.all
或np.any
有机会短路之前就已经被评估了。目前要做得更好,您需要编写专门的C/Cython代码类似于此。 - unutbuand
和 &
根本不是同一回事,它们甚至没有相同的优先级。 - Camion我有同样的问题(即使用多条件索引,这里是在特定日期范围内查找数据)。(a-b).any()
或(a-b).all()
似乎不起作用,至少对我来说是这样。
相反,我找到了另一种完美解决我的期望功能的方法(在尝试索引数组时,一个具有多个元素的数组的真值是模糊的)。
不要使用上面建议的代码,使用以下代码:
numpy.logical_and(a, b)
and
隐式调用bool
,首先在左操作数上执行(如果左操作数为True
),然后在右操作数上执行。因此x and y
相当于bool(x) and bool(y)
。numpy.ndarray
(如果它包含多个元素)上的bool
会抛出你见过的异常:>>> import numpy as np
>>> arr = np.array([1, 2, 3])
>>> bool(arr)
ValueError: The truth value of an array with more than one element is ambiguous. Use a.any() or a.all()
bool()
调用在and
中是隐式的,但在if
,while
和or
中也是隐式的,因此以下任何示例都会失败:
>>> arr and arr
ValueError: The truth value of an array with more than one element is ambiguous. Use a.any() or a.all()
>>> if arr: pass
ValueError: The truth value of an array with more than one element is ambiguous. Use a.any() or a.all()
>>> while arr: pass
ValueError: The truth value of an array with more than one element is ambiguous. Use a.any() or a.all()
>>> arr or arr
ValueError: The truth value of an array with more than one element is ambiguous. Use a.any() or a.all()
在Python中,有更多的函数和语句可以隐藏bool调用,例如2 < x < 10
只是另一种写法,等同于2 < x and x < 10
。而and
将会调用bool
: bool(2 < x) and bool(x < 10)
。and
的等价函数是np.logical_and
,类似地,or
的等价函数是np.logical_or
。<
,<=
,==
,!=
,>=
和>
比较返回布尔NumPy数组 - 也可以使用按元素位运算的功能(和运算符):np.bitwise_and
(&
运算符)。>>> np.logical_and(arr > 1, arr < 3)
array([False, True, False], dtype=bool)
>>> np.bitwise_and(arr > 1, arr < 3)
array([False, True, False], dtype=bool)
>>> (arr > 1) & (arr < 3)
array([False, True, False], dtype=bool)
和bitwise_or
(|
运算符):
>>> np.logical_or(arr <= 1, arr >= 3)
array([ True, False, True], dtype=bool)
>>> np.bitwise_or(arr <= 1, arr >= 3)
array([ True, False, True], dtype=bool)
>>> (arr <= 1) | (arr >= 3)
array([ True, False, True], dtype=bool)
在NumPy文档中可以找到逻辑和二进制函数的完整列表:
a.__bool__()
返回的。根据真值测试中描述的逻辑,Python的bool
可能会调用这个函数,但我对此并不确定,因为这一部分涉及到内置类型。 - minsif np.array([1,2]): print(1)
--> ValueError: The truth value of an array with more than one element is ambiguous. Use a.any() or a.all()
。if np.array([1,2])[0]: print(1)
--> 没有 ValueError,但是:if np.array([])[0]: print(1)
--> IndexError: index 0 is out of bounds for axis 0 with size 0
。if np.array([1]): print(1)
--> 没有 ValueError,但对于包含多个元素的数组也无法帮助。if np.array([]): print(1)
--> DeprecationWarning: The truth value of an empty array is ambiguous. Returning False, but in future this will result in an error. Use 'array.size > 0' to check that an array is not empty.
if np.array([]).size is not None: print(1)
: 根据此用户的评论,这也行不通。这是因为没有任何一个np.array
可以成为None
相同的对象——该对象是唯一的——因此,无论它是否为空,它始终会匹配 is not None
(即永远不会匹配is None
)。if np.array([]).size: print(1)
解决了这个错误。if np.array([]) is not None: print(1)
- lokinp.array
都不可能是与 None
相同的对象 - 该对象是唯一的 - 因此无论它是否为空,它始终会匹配 is not None
(即永远不会匹配 is None
)。 - Karl Knechtelpandas
,那么解决这个问题的方法是在有 NA 值时避免进行计算,正确的做法是运行以下命令:df = df.dropna()
,然后再进行计算即可。无论何时代码试图将Numpy数组转换为布尔值(即检查其“真值”,如错误消息中所述),都会发生此错误。对于给定的数组a
,这可能会发生:
bool(a)
。a and a
、a or a
、not a
。any
和all
函数。(这些函数可以接受一个数组,无论它有多少维;但不能接受一个数组列表、元组、集合等 of arrays。)if
语句中隐式地使用if a:
。虽然通常可以在if
语句中使用任何Python对象,但Numpy数组故意打破了这个功能,因为否则可能会很容易地通过错误编写不正确的代码。
==
,!=
,<
,>
,<=
,>=
)对于Numpy数组,比较具有特殊的含义。我们将在这里考虑==
运算符;其余运算符的行为类似。假设我们有:
import numpy as np
>>> a = np.arange(9)
>>> b = a % 3
>>> a
array([0, 1, 2, 3, 4, 5, 6, 7, 8])
>>> b
array([0, 1, 2, 0, 1, 2, 0, 1, 2])
a == b
并不意味着“给出一个True
或False
的答案:即a是否等于b?”通常情况下它会这样解释。相反地,它将逐个元素比较这些值,并评估这些比较的布尔结果数组。>>> a == b
array([ True, True, True, False, False, False, False, False, False])
换句话说,它执行与数学运算符(如b = a%3
)相同类型的广播。
在if
语句中使用此结果没有意义,因为不清楚该怎么做:我们应该进入if
块,因为一些值匹配了吗?还是我们应该进入else
块,因为一些值没有匹配?在这里,Numpy应用了Python之禅中的一个重要原则:“面对模棱两可的情况,拒绝猜测的诱惑。”
因此,只有当数组包含恰好一个元素时,Numpy才允许将其转换为bool
。(在一些旧版本中,它也会将空数组转换为False
;但是有很好的逻辑原因说明为什么这也应被视为模棱两可。)
同样地,比较 a == 4
并不会 检查数组是否等于整数(当然,任何数组都无法等于任何整数)。相反,它将在整个数组中广播比较,给出类似的结果数组:
>>> a == 4
array([False, False, False, False, True, False, False, False, False])
bool
,则根据需要选择在结果上应用.any
或.all
。正如名称所示,.any
将折叠数组为单个布尔值,指示是否有任何真实值;.all
将检查所有值是否都是真实的。
>>> (a == 4).all() # `a == 4`包含一些`False`值
False
>>> (a == 4).any() # 还有一些`True`值
True
>>> a.all() # 我们也可以直接检查`a`:`0`不是真实的,
False
>>> a.any() # 但`a`中的其他值是。
True
如果目标是逐元素将a
转换为布尔值,则使用a.astype(bool)
或(仅适用于数字输入)a != 0
。and
/or
/not
),则使用位运算符(分别为&
/|
/~
):
>>> ((a % 2) != 0) & ((a % 3) != 0) # 注意是`&`,不是`and`
array([False, True, False, False, False, True, False, True, False])
请注意,位运算符还提供对布尔输入的异或^
的访问;这是逻辑运算符不支持(没有xor
)。all
和any
所做的),请构建相应的(N+1)维数组,并沿轴0使用np.all
或np.any
:
>>> a = np.arange(100) # 用于更复杂计算的较大数组
>>> sieves = [a % p for p in (2, 3, 5, 7)]
>>> all(sieves) # 不起作用
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
ValueError: The truth value of an array with more than one element is ambiguous.
Use a.any() or a.all()
>>> np.all(np.array(sieves), axis=0) # 替代:
array([False, True, False, False, False, False, False, False, False,
False, False, True, False, True, False, False, False, True,
False, True, False, False, False, True, False, False, False,
False, False, True, False, True, False, False, False, False,
False, True, False, False, False, True, False, True, False,
False, False, True, False, False, False, False, False, True,
False, False, False, False, False, True, False, True, False,
False, False, False, False, True, False, False, False, True,
False, True, False, False, False, False, False, True, False,
False, False, True, False, False, False, False, False, True,
False, False, False, False, False, False, False, True, False,
False])
if
语句首先,请记住,如果代码有一个使用错误表达式的if
语句(例如if (a % 3 == 0) or (a % 5 == 0):
),那么两个条件都需要修复。
通常,显式转换为bool(使用上述的.all()
或.any()
)将避免异常:
>>> a = np.arange(20) # enough to illustrate this
>>> if ((a % 3 == 0) | (a % 5 == 0)).any():
... print('there are fizzbuzz values')
...
there are fizzbuzz values
但它可能不会做想要的事情:
>>> a = np.arange(20) # enough to illustrate this
>>> if ((a % 3 == 0) | (a % 5 == 0)).any():
... a = -1
...
>>> a
-1
>>> a = np.arange(20)
>>> a[(a % 3 == 0) | (a % 5 == 0)] = -1
>>> a
array([-1, 1, 2, -1, 4, -1, -1, 7, 8, -1, -1, 11, -1, 13, 14, -1, 16,
17, -1, 19])
这种索引技术也适用于查找满足条件的值。在之前的sieves
示例的基础上:
>>> a = np.arange(100)
>>> sieves = [a % p for p in (2, 3, 5, 7)]
>>> a[np.all(np.array(sieves), axis=0)]
array([ 1, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71,
73, 79, 83, 89, 97])
(练习:研究代码并理解为什么这个结果“不完全”是100以下的质数列表;然后修复它。)
Pandas库依赖于Numpy,并在Numpy的数组类型之上实现了其DataFrame
类型。所有相同的推理都适用,因此Pandas Series
(和DataFrame
)对象不能用作布尔值:请参见系列的真值是模棱两可的。使用a.empty、a.bool()、a.item()、a.any()或a.all()。
解决问题的Pandas接口有点更复杂 - 最好通过阅读该Q&A来理解。该问题特别涵盖了Series,但逻辑通常也适用于DataFrames。如果您需要更具体的指导,请参见带有数据框的条件。
这个错误信息也会在进行if语句
比较时出现,其中涉及到一个数组和一个布尔值或整数。例如:
... code snippet ...
if dataset == bool:
....
... code snippet ...
此子句具有数据集作为数组,布尔值为“开放式门”... True
或False
。
如果该函数被包装在一个try语句
中,您将会收到带有except Exception as error:
的消息,但没有错误类型:
一个具有多个元素的数组的真实价值是模棱两可的,请使用a.any() 或 a.all()
a = np.array([1, 2, 3])
b = np.array([2, 3, 4])
if b >= a:
吗?a
和 b
不是单个数字,实际上你的意思是如果 b
的每个元素都大于相应的 a
中的数字,那么你应该使用以下命令:if (b >= a).all():
print("b is greater than a!")
>>> import numpy as np
>>> arr = np.array([1, 4, 2, 7, 5])
>>> arr[(arr > 3) and (arr < 6)] # this will fail
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
ValueError: The truth value of an array with more than one element is ambiguous. Use a.any() or a.all()
>>> arr[(arr > 3) & (arr < 6)] # this will succeed
array([4, 5])
对我而言,这个错误发生在测试中,出现错误的代码如下:
pixels = []
self.pixels = numpy.arange(1, 10)
self.assertEqual(self.pixels, pixels)
这段代码返回:
ValueError:具有多个元素的数组的真值不明确。使用a.any()或a.all()
因为我不能用列表断言 numpy 的 arrange 方法返回的对象。
解决方案是将 numpy 的 arrange 对象转换为列表,我的选择是使用 toList()
方法,如下所示:
pixels = []
self.pixels = numpy.arange(1, 10).toList()
self.assertEqual(self.pixels, pixels)
pixels
列表为空,这不允许正确地广播。其次,如果pixels
列表的大小/形状适合广播,则将pixels
与self.pixels
进行比较的结果将是一个Numpy数组,这将打破assertEqual
内部的条件逻辑。但是,确实可以编写类似于self.assertTrue ((numpy.arange(1,10)==range(1,10)).all())
的测试。 - Karl Knechtel.toList
方法更有意义。这将防止测试在被测试的代码返回错误形状的数组时引发异常。 - Karl Knechtel.toList
方法更有意义。这样做可以防止测试在被测试的代码返回形状错误的数组时引发异常。 - Karl Knechtel