Fre*_*Foo 107 python numpy nan
我正在寻找检查np.nanNumPy数组中NaN()出现的最快方法X.np.isnan(X)是不可能的,因为它构建了一个布尔形状的数组X.shape,这可能是巨大的.
我试过了np.nan in X,但这似乎不起作用,因为np.nan != np.nan.有没有一种快速且节省内存的方法来完成这项工作?
(对于那些会问"多么巨大"的人:我说不出来.这是图书馆代码的输入验证.)
NPE*_*NPE 146
Ray的解决方案很好.但是,在我的机器上,它的使用速度提高了约2.5倍numpy.sum,代替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
Run Code Online (Sandbox Code Playgroud)
不同min,sum不需要分支,这在现代硬件上往往相当昂贵.这可能是为什么sum更快的原因.
编辑上面的测试是在阵列中间用一个NaN进行的.
值得注意的是,min在NaN存在下比在不存在时更慢.随着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
Run Code Online (Sandbox Code Playgroud)
eat*_*eat 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
Run Code Online (Sandbox Code Playgroud)
因此,真正有效的方式可能在很大程度上取决于操作系统.无论如何,dot(.)基础似乎是最稳定的.
Nic*_*mer 10
这里有两种通用方法:
nan并获取any.nans(如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)",
)
Run Code Online (Sandbox Code Playgroud)
如果您对numba感到满意,它可以创建一个快速短路(一旦发现 NaN 就停止)函数:
\n\nimport numba as nb\nimport math\n\n@nb.njit\ndef anynan(array):\n array = array.ravel()\n for i in range(array.size):\n if math.isnan(array[i]):\n return True\n return False\nRun Code Online (Sandbox Code Playgroud)\n\n如果没有,NaN该函数实际上可能比 慢np.min,我认为这是因为np.min对大型数组使用多重处理:
import numpy as np\narray = np.random.random(2000000)\n\n%timeit anynan(array) # 100 loops, best of 3: 2.21 ms per loop\n%timeit np.isnan(array.sum()) # 100 loops, best of 3: 4.45 ms per loop\n%timeit np.isnan(array.min()) # 1000 loops, best of 3: 1.64 ms per loop\nRun Code Online (Sandbox Code Playgroud)\n\n但如果数组中有 NaN,特别是如果它的位置处于低索引,那么它会快得多:
\n\narray = np.random.random(2000000)\narray[100] = np.nan\n\n%timeit anynan(array) # 1000000 loops, best of 3: 1.93 \xc2\xb5s per loop\n%timeit np.isnan(array.sum()) # 100 loops, best of 3: 4.57 ms per loop\n%timeit np.isnan(array.min()) # 1000 loops, best of 3: 1.65 ms per loop\nRun Code Online (Sandbox Code Playgroud)\n\n使用 Cython 或 C 扩展可以实现类似的结果,这些结果有点复杂(或者很容易获得bottleneck.anynan),但最终与我的功能相同anynan。
小智 5
使用 .any()
if numpy.isnan(myarray).any()
numpy.isfinite 可能比 isnan 更适合检查
if not np.isfinite(prop).all()