快速检查NumPy中的NaN
我正在寻找最快的方法来检查NumPy数组X
的NaN( np.nan
)的发生。 np.isnan(X)
是np.isnan(X)
的,因为它构build了一个形状为X.shape
的布尔型数组,它可能是巨大的。
我np.nan in X
尝试np.nan in X
,但是这似乎不工作,因为np.nan != np.nan
。 有没有一个快速和有效的方法来做到这一点?
(对那些会问“多么巨大”的人来说:我不能说,这是对库代码的inputvalidation。)
雷的解决scheme是好的。 但是,在我的机器上,使用numpy.sum
代替numpy.min
速度要快2.5倍:
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
与min
不同, sum
不需要分支,在现代硬件上往往是相当昂贵的。 这可能是sum
更快的原因。
编辑上面的testing是在arrays中间用一个单独的NaN执行的。
值得注意的是,在NaN存在的情况下min
比在不存在的情况下慢。 随着NaN接近数组的开始,它似乎也变得越来越慢。 另一方面, sum
的吞吐量似乎是不变的,不pipe是否有NaN和它们的位置:
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
我认为np.isnan(np.min(X))
应该做你想要的。
即使有一个被接受的答案,我想演示下面的内容(在Vista上使用Python 2.7.2和Numpy 1.6.0):
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
因此,真正有效的方式可能严重依赖于操作系统。 无论如何dot(.)
似乎是最稳定的。
如果你对numba感到满意,它可以创build一个快速短路(只要findNaN就停下来)function:
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
如果没有NaN
函数可能实际上比np.min
慢,我认为这是因为np.min
使用多处理大型数组:
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
但是如果在arrays中存在NaN,特别是如果位置处于低指数,则速度要快得多:
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
使用Cython或C扩展可能会得到类似的结果,这些可能会更复杂一些(或者简单地说就像bothne.anynan一样),但是最终会和我的anynan
函数一样。
这里有两种一般的方法:
- 检查每个数组项目
nan
并采取any
。 - 应用一些保留
nan
(如sum
)的累积操作并检查其结果。
虽然第一种方法当然是最干净的,但是对某些累积操作(尤其是那些在BLAS中执行的操作(如dot
))的大量优化可以使这些操作相当快。 请注意,像某些其他BLAS操作一样, dot
在某些情况下是multithreading的。 这解释了不同机器之间的速度差异。
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)' )
与此相关的是如何find第一个NaN的问题。 这是处理我所知道的最快的方法:
index = next((i for (i,n) in enumerate(iterable) if n!=n), None)
enter code here
- 使用.any()
if numpy.isnan(myarray).any()
- numpy.isfinite可能比isnan更好的检查
if not np.isfinite(prop).all()