Numpy „logical_or” dla więcej niż dwóch argumentów


88

logical_orFunkcja Numpy'ego wymaga do porównania nie więcej niż dwóch tablic. Jak znaleźć sumę więcej niż dwóch tablic? (To samo pytanie można zadać w odniesieniu do Numpy'ego logical_andi uzyskania przecięcia więcej niż dwóch tablic).



czy istnieje sposób analogiczny do dowolnego ()?
user3074893

@ user3074893: To jest dokładnie ten sam problem. Chcesz, żebym poszerzył moją odpowiedź?
abarnert

Odpowiedzi:


174

Jeśli o to pytasz numpy.logical_or, to nie, jak wyraźnie mówią dokumenty, jedynymi parametrami są x1, x2i opcjonalnie out:

numpy.logical_or( x1, x2[, out]) =<ufunc 'logical_or'>


Możesz oczywiście łączyć wiele logical_orpołączeń w ten sposób:

>>> 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)

Sposób na uogólnienie tego rodzaju łańcuchów w NumPy jest następujący reduce:

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

I oczywiście to będzie również działać, jeśli masz jeden wielowymiarową tablicę zamiast oddzielnych tablic-w rzeczywistości, to w jaki sposób to oznaczało być stosowane:

>>> 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)

Ale krotka trzech tablic 1D o równej długości jest tablicą podobną do tablicy w terminach NumPy i może być używana jako tablica 2D.


Poza NumPy możesz także używać Pythona reduce:

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

Jednak w przeciwieństwie do NumPy reduce, Python nie jest często potrzebny. W większości przypadków istnieje prostszy sposób wykonywania pewnych czynności - np. Łączenie wielu oroperatorów Pythona w łańcuch , nie reduceprzerywaj operator.or_, po prostu użyj any. A jeśli nie ma , zwykle bardziej czytelne jest użycie jawnej pętli.

W rzeczywistości NumPy anymoże być również używany w tym przypadku, chociaż nie jest to aż tak trywialne; jeśli jawnie nie nadasz mu osi, otrzymasz skalar zamiast tablicy. Więc:

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

Jak można się spodziewać, logical_andjest podobnie - można to połączyć w łańcuch, np.reduceto, functools.reduceto lub zamienić allna jawne axis.

A co z innymi operacjami logical_xor? Ponownie, ta sama umowa… z tym wyjątkiem, że w tym przypadku nie ma zastosowania funkcji all/ any-type. (Jak byś to nazwał odd?)


2
np.logical_or.reduce((x, y, z))był właśnie tym, czego szukałem!
blaylockbk

reducenie jest już funkcją wewnętrzną w Pythonie 3. Zamiast tego użyj:functools.reduce()
marvin

10

W przypadku gdy ktoś nadal potrzebujemy tego - powiedzmy masz trzy tablice logiczne a, b, cz takim samym kształcie, co daje andelement mądry:

a * b * c

to daje or:

a + b + c

Czy to jest to, czego chcesz? Układanie w stos dużo logical_andlub logical_ornie jest praktyczne.


6

Ponieważ algebry boolowskie są z definicji przemienne i asocjacyjne, poniższe instrukcje lub ich odpowiedniki dla wartości boolowskich a, b i c.

a or b or c

(a or b) or c

a or (b or c)

(b or a) or c

Więc jeśli masz „logical_or”, który jest diadyczny i musisz przekazać mu trzy argumenty (a, b i c), możesz wywołać

logical_or(logical_or(a, b), c)

logical_or(a, logical_or(b, c))

logical_or(c, logical_or(b, a))

lub jakąkolwiek permutację lubisz.


Wracając do Pythona, jeśli chcesz sprawdzić, czy warunek (uzyskany przez funkcję, testktóra przyjmuje testowanego i zwraca wartość logiczną) ma zastosowanie do a, b lub c lub dowolnego elementu listy L, zwykle używasz

any(test(x) for x in L)

Ale Python ornie jest tak naprawdę logiczny or, zarówno dlatego, że działa na wartościach innych niż bools (zwraca, ajeśli ajest prawdą, w bprzeciwnym razie), i dlatego, że powoduje zwarcia (co oznacza, że a or bmoże być True, podczas gdy b or azgłasza wyjątek).
abarnert

@abarnert Dziękuję, zredagowałem odpowiedź, aby to uwzględnić.
Hyperboreus,

(Nie jestem pewien, dlaczego ludzie odrzucili to, jednak ... wydaje się, że OP mówi konkretnie o wartościach boolowskich, które nazywa „warunkami logicznymi”.)
abarnert

@abarnert Nie pytaj mnie. Jestem zdania, że ​​jeśli masz proste obliczenia matematyczne (w tym przypadku algebry boolowskie) w tle, wiele problemów programistycznych jest łatwiejszych do rozwiązania.
Hyperboreus,

4

Opierając się na odpowiedzi abarnerta dla przypadku n-wymiarowego:

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


4

używając funkcji sumy:

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)

4

Używam tego obejścia, które można rozszerzyć do n tablic:

>>> 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)

1

Wypróbowałem następujące trzy różne metody, aby uzyskać logical_andlistę l z k tablic o rozmiarze n :

  1. Korzystanie z rekurencyjnego numpy.logical_and(patrz poniżej)
  2. Za pomocą numpy.logical_and.reduce(l)
  3. Za pomocą numpy.vstack(l).all(axis=0)

Następnie zrobiłem to samo dla logical_orfunkcji. O dziwo, metoda rekurencyjna jest najszybsza.

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
)

Poniżej wyniki dla k = 4.

Wydajność dla k = 4

A poniżej wyniki dla k = 10.

Wydajność dla k = 10

Wydaje się, że istnieje w przybliżeniu stały narzut czasowy również dla wyższego n.

Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.