Prueba si la matriz numpy contiene solo ceros

92

Inicializamos una matriz numpy con ceros como se muestra a continuación:

np.zeros((N,N+1))

Pero, ¿cómo verificamos si todos los elementos en una matriz de matriz numérica dada n * n son cero?
El método solo necesita devolver un verdadero si todos los valores son realmente cero.

Desconocido
fuente

Respuestas:

71

Echa un vistazo a numpy.count_nonzero .

>>> np.count_nonzero(np.eye(4))
4
>>> np.count_nonzero([[0,1,7,0,0],[3,0,0,2,19]])
5
Prashant Kumar
fuente
9
Querrá not np.count_nonzero(np.eye(4))regresar Truesolo si todos los valores son 0.
J. Martinot-Lagarde
161

Las otras respuestas publicadas aquí funcionarán, pero la función más clara y eficiente para usar es numpy.any():

>>> all_zeros = not np.any(a)

o

>>> all_zeros = not a.any()
  • Se prefiere numpy.all(a==0)esto porque usa menos RAM. (No requiere la matriz temporal creada por el a==0término).
  • Además, es más rápido numpy.count_nonzero(a)porque puede regresar inmediatamente cuando se ha encontrado el primer elemento distinto de cero.
    • Editar: Como @Rachel señaló en los comentarios, np.any()ya no usa la lógica de "cortocircuito", por lo que no verá un beneficio de velocidad para arreglos pequeños.
Stuart Berg
fuente
2
A partir de hace un minuto, numpy de anyy allhacer no cortocircuito. Creo que son azúcar para logical_or.reducey logical_and.reduce. Compárense entre sí y mi cortocircuito is_in: all_false = np.zeros(10**8) all_true = np.ones(10**8) %timeit np.any(all_false) 91.5 ms ± 1.82 ms per loop %timeit np.any(all_true) 93.7 ms ± 6.16 ms per loop %timeit is_in(1, all_true) 293 ns ± 1.65 ns per loop
Rachel
2
Ese es un gran punto, gracias. Parece que el cortocircuito solía ser el comportamiento, pero eso se perdió en algún momento. Hay una discusión interesante en las respuestas a esta pregunta .
Stuart Berg
50

Usaría np.all aquí, si tiene una matriz a:

>>> np.all(a==0)
J. Martinot-Lagarde
fuente
3
Me gusta que esta respuesta también verifique valores distintos de cero. Por ejemplo, se puede comprobar si todos los elementos de una matriz son iguales haciendo np.all(a==a[0]). ¡Muchas gracias!
aignas
9

Como dice otra respuesta, puede aprovechar las evaluaciones de verdad / falsedad si sabe que 0es el único elemento falso posiblemente en su matriz. Todos los elementos de una matriz son falsos si no hay elementos veraces en ella. *

>>> a = np.zeros(10)
>>> not np.any(a)
True

Sin embargo, la respuesta afirmó que anyera más rápido que otras opciones debido en parte al cortocircuito. A partir de 2018, Numpy's ally any no cortocircuito .

Si hace este tipo de cosas con frecuencia, es muy fácil crear sus propias versiones de cortocircuito usando numba:

import numba as nb

# short-circuiting replacement for np.any()
@nb.jit(nopython=True)
def sc_any(array):
    for x in array.flat:
        if x:
            return True
    return False

# short-circuiting replacement for np.all()
@nb.jit(nopython=True)
def sc_all(array):
    for x in array.flat:
        if not x:
            return False
    return True

Estos tienden a ser más rápidos que las versiones de Numpy incluso cuando no están en cortocircuito. count_nonzeroes el más lento.

Algunas aportaciones para comprobar el rendimiento:

import numpy as np

n = 10**8
middle = n//2
all_0 = np.zeros(n, dtype=int)
all_1 = np.ones(n, dtype=int)
mid_0 = np.ones(n, dtype=int)
mid_1 = np.zeros(n, dtype=int)
np.put(mid_0, middle, 0)
np.put(mid_1, middle, 1)
# mid_0 = [1 1 1 ... 1 0 1 ... 1 1 1]
# mid_1 = [0 0 0 ... 0 1 0 ... 0 0 0]

Cheque:

## count_nonzero
%timeit np.count_nonzero(all_0) 
# 220 ms ± 8.73 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
%timeit np.count_nonzero(all_1)
# 150 ms ± 4.56 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)

### all
# np.all
%timeit np.all(all_1)
%timeit np.all(mid_0)
%timeit np.all(all_0)
# 56.8 ms ± 3.41 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)
# 57.4 ms ± 1.76 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)
# 55.9 ms ± 2.13 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)

# sc_all
%timeit sc_all(all_1)
%timeit sc_all(mid_0)
%timeit sc_all(all_0)
# 44.4 ms ± 2.49 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)
# 22.7 ms ± 599 µs per loop (mean ± std. dev. of 7 runs, 10 loops each)
# 288 ns ± 6.36 ns per loop (mean ± std. dev. of 7 runs, 1000000 loops each)

### any
# np.any
%timeit np.any(all_0)
%timeit np.any(mid_1)
%timeit np.any(all_1)
# 60.7 ms ± 1.38 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)
# 60 ms ± 287 µs per loop (mean ± std. dev. of 7 runs, 10 loops each)
# 57.7 ms ± 1.12 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)

# sc_any
%timeit sc_any(all_0)
%timeit sc_any(mid_1)
%timeit sc_any(all_1)
# 41.7 ms ± 1.24 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)
# 22.4 ms ± 1.51 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)
# 287 ns ± 12.7 ns per loop (mean ± std. dev. of 7 runs, 1000000 loops each)

* Útil ally anyequivalencias:

np.all(a) == np.logical_not(np.any(np.logical_not(a)))
np.any(a) == np.logical_not(np.all(np.logical_not(a)))
not np.all(a) == np.any(np.logical_not(a))
not np.any(a) == np.all(np.logical_not(a))
Raquel
fuente
-9

Si está probando todos los ceros para evitar una advertencia en otra función numérica, luego envuelva la línea en un intento, excepto que el bloque le ahorrará tener que hacer la prueba de ceros antes de la operación que le interesa, es decir.

try: # removes output noise for empty slice 
    mean = np.mean(array)
except:
    mean = 0
ReaddyEddy
fuente