我刚刚在代码中发现了一个逻辑错误,导致了各种各样的问题.我无意中做了一个按位AND而不是逻辑AND.
我更改了代码:
r = mlab.csv2rec(datafile, delimiter=',', names=COL_HEADERS)
mask = ((r["dt"] >= startdate) & (r["dt"] <= enddate))
selected = r[mask]
Run Code Online (Sandbox Code Playgroud)
至:
r = mlab.csv2rec(datafile, delimiter=',', names=COL_HEADERS)
mask = ((r["dt"] >= startdate) and (r["dt"] <= enddate))
selected = r[mask]
Run Code Online (Sandbox Code Playgroud)
令我惊讶的是,我收到了相当神秘的错误消息:
ValueError:具有多个元素的数组的真值是不明确的.使用a.any()或a.all()
为什么在使用按位操作时没有发出类似的错误 - 我该如何解决这个问题?
unu*_*tbu 146
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]
Run Code Online (Sandbox Code Playgroud)
看起来不错.但是,如果你想要and,那么而不是a and b使用(a-b).any()或(a-b).all().
Yeq*_*ang 40
我有同样的问题(即使用多条件索引,这里它在某个日期范围内查找数据).在(a-b).any()或(a-b).all()似乎不工作,至少对我来说.
或者,我找到了另一种解决方案,它可以完美地满足我所需的功能(/sf/ask/885323001/ -when-trying-t).
不使用上面建议的代码,只需使用一个numpy.logical_and(a,b)就行了.在这里,您可能希望将代码重写为
(a-b).any()
MSe*_*ert 24
异常的原因是and隐式调用bool.首先在左操作数和(如果左操作数是True)然后在右操作数上.所以x and y相当于bool(x) and bool(y).
但是boolon numpy.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()
Run Code Online (Sandbox Code Playgroud)
在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()
Run Code Online (Sandbox Code Playgroud)
Python中有更多隐藏bool调用的函数和语句,例如2 < x < 10只是另一种编写方式2 < x and x < 10.而and将调用bool:bool(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)
Run Code Online (Sandbox Code Playgroud)
和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)
Run Code Online (Sandbox Code Playgroud)
可以在NumPy文档中找到逻辑和二进制函数的完整列表:
每当代码尝试将 Numpy 数组转换为布尔值(即检查其真值,如错误消息中所述)时,都会发生此错误。对于给定的 array a,可能会发生这种情况:
明确地,通过使用bool(a).
隐式使用布尔逻辑运算符:a and a, a or a, not a。
隐式使用内置的any和all函数。(它们可以接受单个数组,无论它有多少维;但不能接受数组的列表、元组、集合等。)
在if声明中隐含地使用if a:. 虽然通常可以在语句中使用任何 Python 对象if,但 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])
Run Code Online (Sandbox Code Playgroud)
然后,a == b 并不意味着“给出一个True或False答案:a等于b?”,就像通常的意思一样。相反,它将逐个元素比较值,并计算出这些比较的布尔结果数组:
>>> a == b
array([ True, True, True, False, False, False, False, False, False])
Run Code Online (Sandbox Code Playgroud)
换句话说,它执行与数学运算符(如)相同类型的广播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])
Run Code Online (Sandbox Code Playgroud)
bool,请根据需要选择应用.any或.all应用于结果。正如名字所暗示的那样,.any将数组折叠为单个布尔值,指示任何值是否为真;.all将检查所有值是否为真。
>>> (a == 4).all() # `a == 4` contains some `False` values
False
>>> (a == 4).any() # and also some `True` values
True
>>> a.all() # We can check `a` directly as well: `0` is not truthy,
False
>>> a.any() # but other values in `a` are.
True
Run Code Online (Sandbox Code Playgroud)
如果目标是按a元素转换为布尔值,请使用a.astype(bool), or (仅适用于数字输入)a != 0。and) or,not请使用按位运算符( &//|~:
>>> ((a % 2) != 0) & ((a % 3) != 0) # N.B. `&`, not `and`
array([False, True, False, False, False, True, False, True, False])
Run Code Online (Sandbox Code Playgroud)^请注意,按位运算符还提供对布尔输入的异或的
访问;逻辑运算符不支持此功能(没有xor)。all和 的any作用),请改为构建相应的 (N+1) 维数组,并沿轴 0使用np.all或np.any:
>>> a = np.arange(100) # a larger array for a more complex calculation
>>> sieves = [a % p for p in (2, 3, 5, 7)]
>>> all(sieves) # won't work
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) # instead:
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])
Run Code Online (Sandbox Code Playgroud)
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
Run Code Online (Sandbox Code Playgroud)
但它可能不会做我们想要的事情:
>>> a = np.arange(20) # enough to illustrate this
>>> if ((a % 3 == 0) | (a % 5 == 0)).any():
... a = -1
...
>>> a
-1
Run Code Online (Sandbox Code Playgroud)
如果目标是对条件为 true 的每个值进行操作,那么自然的方法就是使用结果数组作为掩码。例如,要在条件为真的任何地方分配新值,只需使用计算出的掩码索引到原始数组,然后分配:
>>> 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])
Run Code Online (Sandbox Code Playgroud)
此索引技术对于查找满足条件的值也很有用。基于前面的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])
Run Code Online (Sandbox Code Playgroud)
(练习:研究代码并理解为什么这个结果不完全是100 以下素数的列表;然后修复它。)
Pandas 库将 Numpy 作为依赖项,并DataFrame在 Numpy 的数组类型之上实现其类型。所有相同的推理都适用,因此 Pandas Series(和DataFrame)对象不能用作 boolean:请参阅系列的真值不明确。使用 a.empty、a.bool()、a.item()、a.any() 或 a.all()。
用于解决该问题的 Pandas 界面有点复杂 - 最好通过阅读问答来理解。该问题具体涉及系列,但逻辑通常也适用于数据帧。另请参阅数据帧的 If 条件,以获取将条件逻辑应用于数据帧的更具体指导。
| 归档时间: |
|
| 查看次数: |
505106 次 |
| 最近记录: |