Necesito calcular la cantidad de elementos que no son NaN en una matriz ndarray numpy. ¿Cómo se podría hacer esto de manera eficiente en Python? Aquí está mi código simple para lograr esto:
import numpy as np
def numberOfNonNans(data):
count = 0
for i in data:
if not np.isnan(i):
count += 1
return count
¿Hay una función incorporada para esto en numpy? La eficiencia es importante porque estoy haciendo análisis de Big Data.
¡Gracias por cualquier ayuda!
sum(not np.isnan(x) for x in a)
, pero en términos de velocidad es lenta en comparación con la versión numpy de @ M4rtini.Respuestas:
~
invierte la matriz booleana devueltanp.isnan
.np.count_nonzero
cuenta valores que no es 0 \ falso..sum
debería dar el mismo resultado. Pero tal vez sea más claro para usarcount_nonzero
Velocidad de prueba:
In [23]: data = np.random.random((10000,10000)) In [24]: data[[np.random.random_integers(0,10000, 100)],:][:, [np.random.random_integers(0,99, 100)]] = np.nan In [25]: %timeit data.size - np.count_nonzero(np.isnan(data)) 1 loops, best of 3: 309 ms per loop In [26]: %timeit np.count_nonzero(~np.isnan(data)) 1 loops, best of 3: 345 ms per loop In [27]: %timeit data.size - np.isnan(data).sum() 1 loops, best of 3: 339 ms per loop
data.size - np.count_nonzero(np.isnan(data))
parece apenas ser el más rápido aquí. otros datos pueden dar diferentes resultados de velocidad relativa.fuente
numpy.isnan(array).sum()
? Sin embargo, no soy muy competente con numpy.data.size - np.isnan(data).sum()
será un poco más eficiente.Alternativa de escritura rápida
Aunque no es la opción más rápida, si el rendimiento no es un problema, puede utilizar:
sum(~np.isnan(data))
.Actuación:
In [7]: %timeit data.size - np.count_nonzero(np.isnan(data)) 10 loops, best of 3: 67.5 ms per loop In [8]: %timeit sum(~np.isnan(data)) 10 loops, best of 3: 154 ms per loop In [9]: %timeit np.sum(~np.isnan(data)) 10 loops, best of 3: 140 ms per loop
fuente
len
en su lugar.Para determinar si la matriz es escasa, puede ser útil obtener una proporción de valores nan
Si esa proporción supera un umbral, utilice una matriz dispersa, por ejemplo: https://sparse.pydata.org/en/latest/
fuente
Una alternativa, pero un poco más lenta, es hacerlo sobre indexación.
np.isnan(data)[np.isnan(data) == False].size In [30]: %timeit np.isnan(data)[np.isnan(data) == False].size 1 loops, best of 3: 498 ms per loop
El doble uso de
np.isnan(data)
y el==
operador podría ser un poco exagerado, por lo que publiqué la respuesta solo para completar.fuente