ValueError:具有多个元素的数组的真值不明确。使用a.any()或a.all()


219

我刚刚在代码中发现了一个逻辑错误,该错误导致了各种各样的问题。我在无意中执行了按位AND运算,而不是逻辑AND 运算

我将代码从:

r = mlab.csv2rec(datafile, delimiter=',', names=COL_HEADERS)
mask = ((r["dt"] >= startdate) & (r["dt"] <= enddate))
selected = r[mask]

至:

r = mlab.csv2rec(datafile, delimiter=',', names=COL_HEADERS)
mask = ((r["dt"] >= startdate) and (r["dt"] <= enddate))
selected = r[mask]

令我惊讶的是,我得到了一个相当神秘的错误消息:

ValueError:具有多个元素的数组的真值不明确。使用a.any()或a.all()

为什么在使用按位操作时没有发出类似的错误-如何解决此问题?


1
熊猫报价文档的这个问题,以及
格雷格-

Answers:


164

r是一个numpy(rec)数组。r["dt"] >= startdate(布尔)数组也是如此。对于numpy数组,该&操作返回两个布尔数组的elementwise和。

该NumPy的开发者觉得有没有人通常理解的方式来评估布尔上下文中的数组:这可能意味着True,如果任何元素 True,或者它可能意味着True,如果所有元素True,或者True如果该数组有非0的长度,只是说出三种可能性。

由于不同的用户可能有不同的需求和不同的假设,因此NumPy开发人员拒绝猜测,而是决定在有人尝试在布尔上下文中评估数组时引发ValueError。应用于and两个numpy数组将导致两个数组在布尔上下文中求值(通过__bool__在Python3或__nonzero__Python2中调用)。

您的原始代码

mask = ((r["dt"] >= startdate) & (r["dt"] <= enddate))
selected = r[mask]

看起来很正确。但是,如果确实需要and,则可以a and b使用(a-b).any()或代替(a-b).all()


2
你是对的。原始代码是正确的。该错误似乎在代码的其他地方。
Homunculus Reticulli 2012年

2
很好的解释。但是,这意味着NumPy效率很低:它可以完全评估两个布尔数组,而有效的实现将在一个循环内评估cond1(i)&& cond2(i),除非cond1为true,否则跳过cond2。
约阿希姆·W

@JoachimWuttke:尽管np.all并且np.any能够短路,但是传递给它的参数在短路之前被评估np.allnp.any有机会短路。为了做得更好,目前,您必须编写类似于this的专用C / Cython代码。
unutbu

47

我遇到了同样的问题(即使用多条件建立索引,这里是在某个日期范围内查找数据)。在(a-b).any()(a-b).all()似乎不工作,至少对我来说。

或者,我找到了另一种解决方案,该解决方案非常适合我所需的功能(尝试对数组进行索引时,包含多个元素的数组的真值不明确)。

除了使用上面建议的代码外,只需使用a即可numpy.logical_and(a,b)。在这里,您可能希望将代码重写为

selected  = r[numpy.logical_and(r["dt"] >= startdate, r["dt"] <= enddate)]

34

发生异常的原因是and隐式调用bool。首先在左侧操作数上(如果左侧操作数为True),然后在右侧操作数上。所以x and y等于bool(x) and bool(y)

然而,boolnumpy.ndarray(如果它包含多个元素)将抛出你已经看到了异常:

>>> 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,而且在ifwhileor,所以任何的下面的示例也将失败:

>>> 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将调用boolbool(2 < x) and bool(x < 10)

元素方面等价物and将是np.logical_and功能,同样可以使用np.logical_or等同的or

对于布尔数组-和比较喜欢的<<===!=>=>对NumPy的数组返回布尔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文档中找到:


2

如果您使用的pandas是为我解决问题的方法,那就是当我有NA值时我正在尝试进行计算,则解决方案是运行:

df = df.dropna()

之后,计算失败。


0

if-statement在有数组(例如bool或int)的地方进行比较时,也会显示这种类型的错误消息。参见例如:

... code snippet ...

if dataset == bool:
    ....

... code snippet ...

此子句的数据集为数组,布尔值为“开门” ... TrueFalse

如果函数包装在a中,则try-statement您将收到except Exception as error:消息,且消息中没有错误类型:

具有多个元素的数组的真值是不明确的。使用a.any()或a.all()


By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.