问题:快速检查NumPy中的NaN
我正在寻找最快的方法来检查np.nan
NumPy数组中NaN()的出现X
。np.isnan(X)
毫无疑问,因为它会构建一个shape的布尔数组X.shape
,这可能是巨大的。
我试过了np.nan in X
,但这似乎不起作用,因为np.nan != np.nan
。有没有一种快速且节省内存的方法来做到这一点?
(对于那些问“多么巨大”的人:我不知道。这是库代码的输入验证。)
回答 0
雷的解决方案很好。但是,在我的机器上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
是,NaNs的存在比NaNs的存在慢。随着NaN越来越接近数组的开始,它似乎也变得越来越慢。另一方面,sum
无论是否存在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
回答 1
我认为np.isnan(np.min(X))
应该做你想要的。
回答 2
即使存在公认的答案,我也想演示以下内容(在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
这里有两种通用方法:
- 检查每个数组项以
nan
获取any
。 - 应用一些保留
nan
s的累积操作(如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
使用.any()
if numpy.isnan(myarray).any()
numpy.isfinite可能比isnan更好
if not np.isfinite(prop).all()
回答 5
如果您满意 麻巴 它允许创建快速短路(找到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
回答 6
与此相关的是如何找到首次出现的NaN的问题。这是我所知道的最快的处理方式:
index = next((i for (i,n) in enumerate(iterable) if n!=n), None)