Numpy `logical_or` for more than two arguments

后端 未结 7 850
庸人自扰
庸人自扰 2020-11-22 09:33

Numpy\'s logical_or function takes no more than two arrays to compare. How can I find the union of more than two arrays? (The same question could be asked wit

相关标签:
7条回答
  • 2020-11-22 09:48

    As boolean algebras are both commutative and associative by definition, the following statements or equivalent for boolean values of a, b and c.

    a or b or c

    (a or b) or c

    a or (b or c)

    (b or a) or c

    So if you have a "logical_or" which is dyadic and you need to pass it three arguments (a, b, and c), you can call

    logical_or(logical_or(a, b), c)

    logical_or(a, logical_or(b, c))

    logical_or(c, logical_or(b, a))

    or whatever permutation you like.


    Back to python, if you want to test whether a condition (yielded by a function test that takes a testee and returns a boolean value) applies to a or b or c or any element of list L, you normally use

    any(test(x) for x in L)
    
    0 讨论(0)
  • 2020-11-22 09:53

    I use this workaround which can be extended to n arrays:

    >>> 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)
    
    0 讨论(0)
  • 2020-11-22 09:54

    using the sum function:

    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)
    
    0 讨论(0)
  • 2020-11-22 09:56

    Building on abarnert's answer for n-dimensional case:

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

    0 讨论(0)
  • 2020-11-22 10:08

    I've tried the following three different methods to get the logical_and of a list l of k arrays of size n:

    1. Using a recursive numpy.logical_and (see below)
    2. Using numpy.logical_and.reduce(l)
    3. Using numpy.vstack(l).all(axis=0)

    Then I did the same for the logical_or function. Surprisingly enough, the recursive method is the fastest one.

    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
    )
    

    Here below the performances for k = 4.

    And here below the performances for k = 10.

    It seems that there is an approximately constant time overhead also for higher n.

    0 讨论(0)
  • 2020-11-22 10:09

    In case someone still need this - Say you have three Boolean arrays a, b, c with the same shape, this gives and element-wise:

    a * b * c
    

    this gives or:

    a + b + c
    

    Is this what you want? Stacking a lot of logical_and or logical_or is not practical.

    0 讨论(0)
提交回复
热议问题