Numpy `logic_or` para más de dos argumentos

Resuelto user3074893 asked hace 11 años • 0 respuestas

La función de Numpy logical_orno requiere más de dos matrices para comparar. ¿Cómo puedo encontrar la unión de más de dos arreglos? (Se podría hacer la misma pregunta con respecto a Numpy logical_andy obtener la intersección de más de dos matrices).

user3074893 avatar Dec 12 '13 02:12 user3074893
Aceptado

Si está preguntando acerca de numpy.logical_or, entonces no, como dicen explícitamente los documentos, los únicos parámetros son x1, x2y, opcionalmente out:

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


Por supuesto, puedes encadenar varias logical_orllamadas de esta manera:

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

La forma de generalizar este tipo de encadenamiento en NumPy es con reduce:

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

Y, por supuesto, esto también funcionará si tiene una matriz multidimensional en lugar de matrices separadas; de hecho, así es como debe usarse :

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

Pero una tupla de tres matrices 1D de igual longitud es similar a una matriz en términos de NumPy y puede usarse como una matriz 2D.


Fuera de NumPy, también puedes usar Python reduce:

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

Sin embargo, a diferencia de NumPy reduce, Python no suele ser necesario. En la mayoría de los casos, existe una forma más sencilla de hacer las cosas; por ejemplo, para encadenar varios oroperadores de Python, no reducesobrecargues operator.or_, solo usa any. Y cuando no lo hay , suele ser más legible utilizar un bucle explícito.

Y, de hecho, NumPy anytambién se puede utilizar para este caso, aunque no es tan trivial; Si no le asignas explícitamente un eje, terminarás con un escalar en lugar de una matriz. Entonces:

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

Como es de esperar, logical_andes similar: puedes encadenarlo, np.reduceit, functools.reduceit o sustituirlo allpor un explícito axis.

¿Qué pasa con otras operaciones, como logical_xor? Nuevamente, lo mismo... excepto que en este caso no se aplica ninguna función de tipo all/ . any(¿Como lo llamarias? odd?)

abarnert avatar Dec 11 '2013 19:12 abarnert

En caso de que alguien todavía necesite esto, digamos que tiene tres matrices booleanas , acon la misma forma, esto proporciona elementos:bcand

a * b * c

esto da or:

a + b + c

¿Es esto lo que quieres? Apilar muchos logical_ando logical_orno es práctico.

Alex avatar Aug 04 '2017 22:08 Alex

Aprovechando la respuesta de abarnert para el caso n-dimensional:

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

citynorman avatar Jan 29 '2017 14:01 citynorman

Como las álgebras booleanas son conmutativas y asociativas por definición, las siguientes declaraciones o equivalentes para valores booleanos de a, b y c.

a or b or c

(a or b) or c

a or (b or c)

(b or a) or c

Entonces, si tiene un "lógico_o" que es diádico y necesita pasarle tres argumentos (a, b y c), puede llamar

logical_or(logical_or(a, b), c)

logical_or(a, logical_or(b, c))

logical_or(c, logical_or(b, a))

o cualquier permutación que quieras.


Volviendo a Python, si desea probar si una condición (producida por una función testque toma a un evaluado y devuelve un valor booleano) se aplica a aoboc o cualquier elemento de la lista L, normalmente usa

any(test(x) for x in L)
Hyperboreus avatar Dec 11 '2013 19:12 Hyperboreus

Probé los siguientes tres métodos diferentes para obtener logical_anduna lista l de k matrices de tamaño n :

  1. Usando un recursivo numpy.logical_and(ver más abajo)
  2. Usandonumpy.logical_and.reduce(l)
  3. Usandonumpy.vstack(l).all(axis=0)

Luego hice lo mismo para la logical_orfunción. Sorprendentemente, el método recursivo es el más rápido.

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
)

A continuación se muestran los rendimientos para k = 4.

Rendimientos para k=4

Y aquí abajo los rendimientos para k = 10.

Rendimientos para k=10

Parece que hay una sobrecarga de tiempo aproximadamente constante también para n más alto.

Giancarlo Sportelli avatar May 27 '2020 22:05 Giancarlo Sportelli