Python 在numpy数组中有效地计数零元素?

Python 在numpy数组中有效地计数零元素?,python,arrays,performance,numpy,multidimensional-array,Python,Arrays,Performance,Numpy,Multidimensional Array,我需要计算numpy数组中的零元素数。我知道这个函数,但似乎没有用于计算零元素的模拟 我的阵列不是很大(通常小于1E5个元素),但操作执行了数百万次 当然,我可以使用len(arr)-np.count\u nonzero(arr),但我想知道是否有更有效的方法 以下是我目前是如何做到这一点的: import numpy as np import timeit arrs = [] for _ in range(1000): arrs.append(np.random.randint(-5

我需要计算
numpy
数组中的零元素数。我知道这个函数,但似乎没有用于计算零元素的模拟

我的阵列不是很大(通常小于1E5个元素),但操作执行了数百万次

当然,我可以使用
len(arr)-np.count\u nonzero(arr)
,但我想知道是否有更有效的方法

以下是我目前是如何做到这一点的:

import numpy as np
import timeit

arrs = []
for _ in range(1000):
    arrs.append(np.random.randint(-5, 5, 10000))


def func1():
    for arr in arrs:
        zero_els = len(arr) - np.count_nonzero(arr)


print(timeit.timeit(func1, number=10))

2x更快的方法是仅使用,但根据需要使用条件

In [3]: arr
Out[3]: 
array([[1, 2, 0, 3],
      [3, 9, 0, 4]])

In [4]: np.count_nonzero(arr==0)
Out[4]: 2

In [5]:def func_cnt():
            for arr in arrs:
                zero_els = np.count_nonzero(arr==0)
                # here, it counts the frequency of zeroes actually
您也可以使用,但速度比


效率:(按降序排列)


更多带加速器的加速功能

如果您可以使用加速器(GPU/TPU),现在就可以通过帮助实现3个数量级以上的速度提升。使用JAX的另一个优点是,NumPy代码只需很少的修改即可使其与JAX兼容。下面是一个可复制的示例:

In [1]: import jax.numpy as jnp
In [2]: from jax import jit

# set up inputs
In [3]: arrs = []
In [4]: for _ in range(1000):
   ...:     arrs.append(np.random.randint(-5, 5, 10000))

# JIT'd function that performs the counting task
In [5]: @jit
   ...: def func_cnt():
   ...:     for arr in arrs:
   ...:         zero_els = jnp.count_nonzero(arr==0)


np.where
使用
np.count\u nonzero
(在编译级别)来确定它返回的数组的大小。将其放入函数调用中以进行公平比较。。。在这种情况下,OP的方法得到的是1ms而不是160us……我已经尝试过了,它的剃须速度只比
func1
所用时间的10%略快。新函数比我原来的函数快2倍。我想这是最好的了。非常感谢。在我的numpy版本为1.12.1且列表中有1000个阵列的计算机上,我得到func1:1000个循环,每个循环的最佳值为3:376µs,func_cnt:1000个循环,每个循环的最佳值为3:1.65 ms。所以我现在很困惑。
count\u nonzero
是一个非常基本的编译操作。无论您想知道零的数量还是非零的数量,您仍然必须遍历整个数组。让numpy在编译代码中这样做,不要担心效率。为什么你认为
len(arr)-np.count\u nonzero(arr)
是低效的?count\u nonzero和潜在count\u zero之间的差是一个减法。这与您将获得的效率差不多。@juanpa.arrivillaga
len(arr)
是通过函数调用进行的属性查找。纯属性查找
a.size
花费的时间减少了25%。@DYZ是的,无论如何都应该使用
a.size
,特别是因为
len(a)
将为多维数组给出错误的答案。但我不认为OP指的是。。。
In [8]: %timeit func_cnt()
10 loops, best of 3: 29.2 ms per loop

In [9]: %timeit func1()
10 loops, best of 3: 46.5 ms per loop

In [10]: %timeit func_where()
10 loops, best of 3: 61.2 ms per loop
In [1]: import jax.numpy as jnp
In [2]: from jax import jit

# set up inputs
In [3]: arrs = []
In [4]: for _ in range(1000):
   ...:     arrs.append(np.random.randint(-5, 5, 10000))

# JIT'd function that performs the counting task
In [5]: @jit
   ...: def func_cnt():
   ...:     for arr in arrs:
   ...:         zero_els = jnp.count_nonzero(arr==0)
# efficiency test
In [8]: %timeit func_cnt()
15.6 µs ± 391 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)