change python numpy nan

change - nan python



Verificación rápida de NaN en NumPy (7)

Estoy buscando la manera más rápida de verificar la ocurrencia de NaN ( np.nan ) en una matriz NumPy X np.isnan(X) está fuera de discusión, ya que construye una matriz booleana de forma X.shape , que es potencialmente gigantesca.

np.nan in X , pero parece que no funciona porque np.nan != np.nan . ¿Hay alguna forma rápida y eficiente de memoria para hacer esto?

(Para aquellos que preguntan "qué tan gigantesco": no puedo decir. Esta es la validación de entrada para el código de la biblioteca).


Aquí hay dos enfoques generales:

  • Compruebe cada elemento de la matriz para nan si hay nan y tome any .
  • Aplique una operación acumulativa que preserve nan (como la sum ) y verifique su resultado.

Si bien el primer enfoque es sin duda el más limpio, la gran optimización de algunas de las operaciones acumulativas (particularmente las que se ejecutan en BLAS, como el dot ) puede hacerlas bastante rápidas. Tenga en cuenta que el dot , al igual que otras operaciones BLAS, tiene múltiples subprocesos bajo ciertas condiciones. Esto explica la diferencia de velocidad entre diferentes máquinas.

import numpy import perfplot def min(a): return numpy.isnan(numpy.min(a)) def sum(a): return numpy.isnan(numpy.sum(a)) def dot(a): return numpy.isnan(numpy.dot(a, a)) def any(a): return numpy.any(numpy.isnan(a)) def einsum(a): return numpy.isnan(numpy.einsum(''i->'', a)) perfplot.show( setup=lambda n: numpy.random.rand(n), kernels=[min, sum, dot, any, einsum], n_range=[2**k for k in range(20)], logx=True, logy=True, xlabel=''len(a)'' )


Creo que np.isnan(np.min(X)) debería hacer lo que quieras.


Incluso si existe una respuesta aceptada, me gustaría demostrar lo siguiente (con Python 2.7.2 y Numpy 1.6.0 en Vista):

In []: x= rand(1e5) In []: %timeit isnan(x.min()) 10000 loops, best of 3: 200 us per loop In []: %timeit isnan(x.sum()) 10000 loops, best of 3: 169 us per loop In []: %timeit isnan(dot(x, x)) 10000 loops, best of 3: 134 us per loop In []: x[5e4]= NaN In []: %timeit isnan(x.min()) 100 loops, best of 3: 4.47 ms per loop In []: %timeit isnan(x.sum()) 100 loops, best of 3: 6.44 ms per loop In []: %timeit isnan(dot(x, x)) 10000 loops, best of 3: 138 us per loop

Por lo tanto, la forma realmente eficiente podría depender en gran medida del sistema operativo. De todos modos, la base de dot(.) Parece ser la más estable.


La solución de Ray es buena. Sin embargo, en mi máquina es aproximadamente 2,5 numpy.sum más rápido usar numpy.sum en lugar de numpy.min :

In [13]: %timeit np.isnan(np.min(x)) 1000 loops, best of 3: 244 us per loop In [14]: %timeit np.isnan(np.sum(x)) 10000 loops, best of 3: 97.3 us per loop

A diferencia de min , sum no requiere ramificación, lo que en hardware moderno tiende a ser bastante caro. Esta es probablemente la razón por la sum es más rápido.

editar La prueba anterior se realizó con un único NaN justo en el medio de la matriz.

Es interesante observar que min es más lento en presencia de NaN que en su ausencia. También parece hacerse más lento a medida que los NaN se acercan al inicio de la matriz. Por otro lado, el rendimiento de la sum parece constante independientemente de si hay NaN y dónde se encuentran:

In [40]: x = np.random.rand(100000) In [41]: %timeit np.isnan(np.min(x)) 10000 loops, best of 3: 153 us per loop In [42]: %timeit np.isnan(np.sum(x)) 10000 loops, best of 3: 95.9 us per loop In [43]: x[50000] = np.nan In [44]: %timeit np.isnan(np.min(x)) 1000 loops, best of 3: 239 us per loop In [45]: %timeit np.isnan(np.sum(x)) 10000 loops, best of 3: 95.8 us per loop In [46]: x[0] = np.nan In [47]: %timeit np.isnan(np.min(x)) 1000 loops, best of 3: 326 us per loop In [48]: %timeit np.isnan(np.sum(x)) 10000 loops, best of 3: 95.9 us per loop


Relacionado con esto está la cuestión de cómo encontrar la primera aparición de NaN. Esta es la manera más rápida de manejar lo que yo sé:

index = next((i for (i,n) in enumerate(iterable) if n!=n), None)


Si te sientes cómodo con numba , numba crear una función rápida de cortocircuito (se detiene tan pronto como se encuentre un NaN):

import numba as nb import math @nb.njit def anynan(array): array = array.ravel() for i in range(array.size): if math.isnan(array[i]): return True return False

Si no hay NaN la función podría ser más lenta que np.min , creo que es porque np.min utiliza el multiprocesamiento para matrices grandes:

import numpy as np array = np.random.random(2000000) %timeit anynan(array) # 100 loops, best of 3: 2.21 ms per loop %timeit np.isnan(array.sum()) # 100 loops, best of 3: 4.45 ms per loop %timeit np.isnan(array.min()) # 1000 loops, best of 3: 1.64 ms per loop

Pero en caso de que haya un NaN en la matriz, especialmente si su posición está en índices bajos, entonces es mucho más rápido:

array = np.random.random(2000000) array[100] = np.nan %timeit anynan(array) # 1000000 loops, best of 3: 1.93 µs per loop %timeit np.isnan(array.sum()) # 100 loops, best of 3: 4.57 ms per loop %timeit np.isnan(array.min()) # 1000 loops, best of 3: 1.65 ms per loop

Se pueden lograr resultados similares con Cython o una extensión C, estos son un poco más complicados (o fácilmente disponibles como bottleneck.anynan ) pero, por último, hacen lo mismo que mi función anynan .


enter code here

  1. usar cualquier()

if numpy.isnan(myarray).any()

  1. numpy.isfinite tal vez mejor que isnan para verificar

if not np.isfinite(prop).all()