Numpy `logical_or` 用于两个以上的参数
- 2024-12-16 08:35:00
- admin 原创
- 156
问题描述:
Numpy 的logical_or
函数最多只接受两个数组进行比较。如何找到两个以上数组的并集?(关于 Numpylogical_and
和获取两个以上数组的交集,可以提出同样的问题。)
解决方案 1:
如果你问的是numpy.logical_or
,那么不是,正如文档明确指出的那样,唯一的参数是x1, x2
,和可选的out
:
numpy.
logical_or
(x1, x2[, out]
) =<ufunc 'logical_or'>
当然,你可以logical_or
像这样将多个调用链接在一起:
>>> x = np.array([True, True, False, False])
>>> y = np.array([True, False, True, False])
>>> z = np.array([False, False, False, False])
>>> np.logical_or(np.logical_or(x, y), z)
array([ True, True, True, False], dtype=bool)
在 NumPy 中概括这种链接的方法是reduce
:
>>> np.logical_or.reduce((x, y, z))
array([ True, True, True, False], dtype=bool)
当然,如果您有一个多维数组而不是单独的数组,这也会起作用 - 事实上,这就是它的使用方式:
>>> xyz = np.array((x, y, z))
>>> xyz
array([[ True, True, False, False],
[ True, False, True, False],
[False, False, False, False]], dtype=bool)
>>> np.logical_or.reduce(xyz)
array([ True, True, True, False], dtype=bool)
但是,三个等长一维数组的元组在 NumPy 术语中是一个类似数组的数组,可以用作二维数组。
除了 NumPy 之外,你还可以使用 Python 的reduce
:
>>> functools.reduce(np.logical_or, (x, y, z))
array([ True, True, True, False], dtype=bool)
但是,与 NumPy 不同reduce
,Python 的 并不经常需要。在大多数情况下,有一种更简单的方法可以完成任务 — 例如,要将多个 Pythonor
运算符链接在一起,不要使用reduce
over operator.or_
,只需使用any
。如果没有,使用显式循环通常更具可读性。
事实上,NumPyany
也可以用于这种情况,尽管它不是那么简单;如果你没有明确地给它一个轴,你最终会得到一个标量而不是一个数组。所以:
>>> np.any((x, y, z), axis=0)
array([ True, True, True, False], dtype=bool)
正如您所期望的,logical_and
是类似的 - 您可以链接它、np.reduce
它、functools.reduce
它,或者all
用显式的替换axis
。
那么其他操作呢?比如logical_xor
?同样,情况也一样……只不过在这种情况下没有适用的all
/any
类型函数。(你会怎么称呼它??odd
)
解决方案 2:
如果有人仍然需要这个 - 假设你有三个布尔数组a
,,,具有相同b
的c
形状,这给出and
元素方式:
a * b * c
得出or
:
a + b + c
这是你想要的吗?堆叠很多logical_and
或logical_or
不切实际。
解决方案 3:
基于 abarnert 对 n 维情况的回答:
总结:np.logical_or.reduce(np.array(list))
解决方案 4:
由于布尔代数根据定义既是交换的又是结合的,因此以下语句或等价于布尔值 a、b 和 c。
a or b or c
(a or b) or c
a or (b or c)
(b or a) or c
因此,如果你有一个二元的“logical_or”,并且需要向其传递三个参数(a、b 和 c),你可以调用
logical_or(logical_or(a, b), c)
logical_or(a, logical_or(b, c))
logical_or(c, logical_or(b, a))
或者任何你喜欢的排列。
回到 Python,如果你想测试一个条件(由一个test
接受测试对象并返回布尔值的函数产生)是否适用于 a 或 b 或 c 或列表 L 中的任何元素,你通常使用
any(test(x) for x in L)
解决方案 5:
我尝试了以下三种不同的方法来获取大小为n的k 个数组的logical_and
列表l:
使用递归
numpy.logical_and
(见下文)使用
numpy.logical_and.reduce(l)
使用
numpy.vstack(l).all(axis=0)
然后我对函数做了同样的操作logical_or
。令人惊讶的是,递归方法是最快的。
import numpy
import perfplot
def and_recursive(*l):
if len(l) == 1:
return l[0].astype(bool)
elif len(l) == 2:
return numpy.logical_and(l[0],l[1])
elif len(l) > 2:
return and_recursive(and_recursive(*l[:2]),and_recursive(*l[2:]))
def or_recursive(*l):
if len(l) == 1:
return l[0].astype(bool)
elif len(l) == 2:
return numpy.logical_or(l[0],l[1])
elif len(l) > 2:
return or_recursive(or_recursive(*l[:2]),or_recursive(*l[2:]))
def and_reduce(*l):
return numpy.logical_and.reduce(l)
def or_reduce(*l):
return numpy.logical_or.reduce(l)
def and_stack(*l):
return numpy.vstack(l).all(axis=0)
def or_stack(*l):
return numpy.vstack(l).any(axis=0)
k = 10 # number of arrays to be combined
perfplot.plot(
setup=lambda n: [numpy.random.choice(a=[False, True], size=n) for j in range(k)],
kernels=[
lambda l: and_recursive(*l),
lambda l: and_reduce(*l),
lambda l: and_stack(*l),
lambda l: or_recursive(*l),
lambda l: or_reduce(*l),
lambda l: or_stack(*l),
],
labels = ['and_recursive', 'and_reduce', 'and_stack', 'or_recursive', 'or_reduce', 'or_stack'],
n_range=[2 ** j for j in range(20)],
logx=True,
logy=True,
xlabel="len(a)",
equality_check=None
)
以下是 k = 4 的表现。
下面是 k = 10 的表现。
对于更高的 n,似乎也存在大约恒定的时间开销。
解决方案 6:
我使用这个解决方法,它可以扩展到 n 个数组:
>>> a = np.array([False, True, False, False])
>>> b = np.array([True, False, False, False])
>>> c = np.array([False, False, False, True])
>>> d = (a + b + c > 0) # That's an "or" between multiple arrays
>>> d
array([ True, True, False, True], dtype=bool)
解决方案 7:
使用 sum 函数:
a = np.array([True, False, True])
b = array([ False, False, True])
c = np.vstack([a,b,b])
Out[172]:
array([[ True, False, True],
[False, False, True],
[False, False, True]], dtype=bool)
np.sum(c,axis=0)>0
Out[173]: array([ True, False, True], dtype=bool)
解决方案 8:
a = np.array([True, False, True])
b = np.array([False, False, True])
c = np.array([True, True, True])
d = np.array([True, True, True])
# logical or
lor = (a+b+c+d).astype(bool)
# logical and
land = (a*b*c*d).astype(bool)
解决方案 9:
如果您想要一个简短(可能不是最佳)的函数来对多维布尔掩码执行逻辑与运算,则可以使用这个递归 lambda 函数:
masks_and = lambda *masks : masks[0] if len(masks) == 1 else masks_and(np.logical_and(masks[0], masks[-1]), *masks[1:-1])
result = masks_and(mask1, mask2, ...)
您还可以推广 lambda 函数,以将任何具有分配属性(例如乘法/AND、总和/OR 等)的运算符(2 个参数的函数)应用于任何对象,假设顺序也很重要,如下所示:
fn2args_reduce = lambda fn2args, *args : args[0] if len(args) == 1 else fn2args_reduce(fn2args, fn2args(args[0], args[1]), *args[2:])
result = fn2args_reduce(np.dot, matrix1, matrix2, ... matrixN)
其结果与使用@
numpy 运算符的结果相同):
np.dot(...(np.dot(np.dot(matrix1, matrix2), matrix3)...), matrixN)
例如fn2args_reduce(lambda a,b: a+b, 1,2,3,4,5)
给你 15 - 这些数字的总和(当然你有一个更高效的sum
函数,但我喜欢它)。
对于 N 个参数的函数来说,更广义的模型可能如下所示:
fnNargs_reduce = lambda fnNargs, N, *args : args[0] if len(args) == 1 else fnNargs_reduce(fnNargs, N, fnNargs(*args[:N]), *args[N:])
fnNargs = lambda x1, x2, x3=neutral, ..., xN=neutral: x1 (?) x2 (?) ... (?) xN
其中,中性表示它是 (?) 运算符的中性元素,例如 + 为 0,* 为 1,等等。
为什么?只是为了好玩 :-)
扫码咨询,免费领取项目管理大礼包!