我有一个numpy数组A。我想以一种有效的方式返回A中非零之前的零数,因为它在循环中。

如果A = np.array([0,1,2]),则np.nonzero(A)[0][0]返回1。但是,如果A = np.array([0,0,0])不起作用(在这种情况下,我希望答案3)。而且,如果A很大,并且第一个非零在开始附近,那么这似乎效率很低。

最佳答案

这是一个迭代的Cython版本,如果这是一个严重的瓶颈,这可能是您最好的选择

# saved as file count_leading_zeros.pyx
import numpy as np
cimport numpy as np
cimport cython

DTYPE = np.int
ctypedef np.int_t DTYPE_t

@cython.boundscheck(False)
def count_leading_zeros(np.ndarray[DTYPE_t, ndim=1] a):
    cdef int elements = a.size
    cdef int i = 0
    cdef int count = 0
    while i < elements:
        if a[i] == 0:
            count += 1
        else:
            return count
        i += 1
    return count

这类似于@mtrw的答案,但以 native 速度进行索引。我的Cython有点粗略,因此可能需要进一步改进。

使用几种不同的方法对IPython的一个非常有利的情况进行快速测试
In [1]: import numpy as np

In [2]: import pyximport; pyximport.install()
Out[2]: (None, <pyximport.pyximport.PyxImporter at 0x53e9250>)

In [3]: import count_leading_zeros

In [4]: %paste
def count_leading_zeros_python(x):
    ctr = 0
    for k in x:
        if k == 0:
            ctr += 1
        else:
            return ctr
    return ctr
## -- End pasted text --
In [5]: a = np.zeros((10000000,), dtype=np.int)

In [6]: a[5] = 1

In [7]:

In [7]: %timeit np.min(np.nonzero(np.hstack((a, 1))))
10 loops, best of 3: 91.1 ms per loop

In [8]:

In [8]: %timeit np.where(a)[0][0] if np.shape(np.where(a)[0])[0] != 0  else np.shape(a)[0]
10 loops, best of 3: 107 ms per loop

In [9]:

In [9]: %timeit count_leading_zeros_python(a)
100000 loops, best of 3: 3.87 µs per loop

In [10]:

In [10]: %timeit count_leading_zeros.count_leading_zeros(a)
1000000 loops, best of 3: 489 ns per loop

但是,只有在我有证据(通过探查器)证明这是一个瓶颈时,我才使用这种方法。许多事情看似效率低下,但绝对不值得您花时间去修复。

关于python - 在numpy数组中查找非零之前的零个数,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/23248169/

10-12 18:52