用于两个以上参数的 Numpy `logical_or`

Posted

技术标签:

【中文标题】用于两个以上参数的 Numpy `logical_or`【英文标题】:Numpy `logical_or` for more than two arguments 【发布时间】:2013-12-29 23:14:41 【问题描述】:

Numpy 的logical_or 函数需要不超过两个数组进行比较。如何找到两个以上数组的并集? (对于 Numpy 的logical_and 和获取两个以上数组的交集,可以提出同样的问题。)

【问题讨论】:

any() ? 有没有类似于 any() 的方法? @user3074893:这完全是同一个问题。你想让我扩大我的答案吗? 【参考方案1】:

由于布尔代数在定义上既是交换的又是结合的,下面的陈述或等价于 a、b 和 c 的 boolean 值。

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)

【讨论】:

但是 Python or 并不是真正的布尔值 or,因为它适用于 bools 以外的值(如果 a 是真的,则返回 a,否则返回 b ),并且因为它会短路(意思是 a or b 可能是 True,而 b or a 会引发异常)。 @abarnert 谢谢,我已经编辑了我的答案来说明这一点。 (我不知道为什么人们不赞成这个,但是...... OP 似乎专门谈论布尔值,他称之为“逻辑条件”。) @abarnert 不要问我。我的观点是,如果你在后台把数学(在这种情况下是布尔代数)搞清楚,很多编程问题就更容易解决了。【参考方案2】:

如果您询问的是 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 术语中是 array_like,可以用作二维数组。


在 NumPy 之外,还可以使用 Python 的reduce

>>> functools.reduce(np.logical_or, (x, y, z))
array([ True,  True,  True,  False], dtype=bool)

但是,与 NumPy 的 reduce 不同,Python 并不经常需要。对于大多数情况,有一种更简单的方法来做事——例如,将多个 Python or 运算符链接在一起,不要将 reduce 超过 operator.or_,只需使用 any。当 没有 时,使用显式循环通常更具可读性。

事实上,NumPy 的any 也可以用于这种情况,尽管它不是那么简单;如果你没有明确地给它一个轴,你最终会得到一个标量而不是一个数组。所以:

>>> np.any((x, y, z), axis=0)
array([ True,  True,  True,  False], dtype=bool)

如您所料,logical_and 是相似的——您可以链接它、np.reduce 它、functools.reduce 它,或者用明确的 axis 替换 all

其他操作呢,比如logical_xor?同样,同样的交易......除了在这种情况下没有适用的all/any-type 函数。 (你会怎么称呼它?odd?)

【讨论】:

np.logical_or.reduce((x, y, z)) 正是我想要的! reduce 不再是 python 3 中的内部函数。而是使用:functools.reduce() np.any((x, y, z), axis=0) 是一个完美的解决方案!!!!我用 似乎使用 functools.reduce 比 numpy 自己的 reduce 更快。有人知道为什么吗?【参考方案3】:

基于 abarnert 对 n 维案例的回答:

TL;DR:np.logical_or.reduce(np.array(list))

【讨论】:

【参考方案4】:

如果有人仍然需要这个 - 假设你有三个布尔数组 abc 具有相同的形状,这给出了 and element-wise:

a * b * c

这给了or

a + b + c

这是你想要的吗? 堆叠很多logical_andlogical_or是不切实际的。

【讨论】:

【参考方案5】:

使用求和函数:

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)

【讨论】:

【参考方案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】:

我尝试了以下三种不同的方法来获取大小为 nk 个数组列表 llogical_and

    使用递归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,似乎也存在近似恒定的时间开销。

【讨论】:

尝试将functools.reduce(numpy.logical_and, l)functools.reduce(numpy.logical_or, l) 添加到您的比较中。有趣的是,我发现它们实际上比 k=4k=10 的递归实现要快,尤其是在 len(a) < 10**4 时。【参考方案8】:

如果您想要一个简短的(可能不是最优的)函数来对多维布尔掩码执行逻辑与,您可以使用这个递归 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、sum/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 代表 * 等等。

为什么?只是为了好玩:-)

【讨论】:

【参考方案9】:
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)

【讨论】:

以上是关于用于两个以上参数的 Numpy `logical_or`的主要内容,如果未能解决你的问题,请参考以下文章

比较两个以上的numpy数组

Numpy randn rand 及数组转换

Sumo Logic 和 Cloudwatch 日志不适用于查询源

第83天:NumPy 字符串操作

第83天:NumPy 字符串操作

所有字符串表都会导致 PickleException:ClassDict 构造的预期零参数(用于 numpy.dtype)