我正在寻找检查NumPy数组np.nan
中NaN(X
)出现次数的最快方法。 np.isnan(X)
是不可能的,因为它构建了一个形状为X.shape
的布尔数组,这可能是巨大的。
我尝试了np.nan in X
,但这似乎不起作用,因为np.nan != np.nan
。是否有一种快速且节省内存的方法来完成这项工作?
(对那些会问“多么巨大”的人:我说不出来。这是图书馆代码的输入验证。)
答案 0 :(得分:136)
Ray的解决方案很好。但是,在我的计算机上,使用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
更快的原因。
编辑上面的测试是在阵列中间使用一个NaN进行的。
值得注意的是,min
在存在NaN时比在没有NaN时慢。随着NaN越来越接近数组的开头,它似乎也变慢了。另一方面,无论是否存在NaN以及它们位于何处,sum
的吞吐量似乎都是恒定的:
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
答案 1 :(得分:24)
我认为np.isnan(np.min(X))
应该做你想做的事。
答案 2 :(得分:17)
即使存在一个公认的答案,我也想演示以下内容(在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(.)
似乎是最稳定的。
答案 3 :(得分:7)
这里有两种通用方法:
nan
的每个数组项,然后选择any
。nan
的累积操作(如sum
)并检查其结果。虽然第一种方法肯定是最干净的,但是一些累积操作(特别是在BLAS中执行的那些,如dot
)的大量优化可以使这些操作非常快。请注意,dot
与其他一些BLAS操作一样,在某些条件下是多线程的。这解释了不同机器之间的速度差异。
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)'
)
答案 4 :(得分:2)
如果您对numba感到满意,它可以创建快速短路(一旦找到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
如果没有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
但是如果数组中有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扩展可以获得类似的结果,这些结果有点复杂(或者可以像bottleneck.anynan
那样容易实现)但最终可以与我的anynan
函数一样。
答案 5 :(得分:2)
View
enter code here
if numpy.isnan(myarray).any()
答案 6 :(得分:1)
与此相关的是如何找到第一次出现的NaN的问题。这是处理我所知道的最快的方法:
index = next((i for (i,n) in enumerate(iterable) if n!=n), None)