我有一个(大的)numpy布尔值数组,其中True
表示另一个先前处理过的信号的过零情况。在我的例子中,我只对数组中第一个和最后一个True
值的索引感兴趣,因此我宁愿不使用np.where
或np.argwhere
,以避免不必要地遍历整个数组。
我不想把我的数组转换成list
,而是使用index()
方法。
到目前为止,我想出的最好的解决方案如下:
# Alias for compactness
enum = enumerate
# Example array, desired output = (3, -5))
a = np.array([False, False, False, True, ..., True, False, False, False, False])
out = next(idx for idx in zip((i for i, x in enum(a) if x), (-i-1 for i, x in enum(a[::-1]) if x)))
print(out)
# (3, -5)
但我还是觉得它有点笨重,想知道Numpy是否已经用另一种语法实现了这样的功能,是吗?
3条答案
按热度按时间jtjikinw1#
使用numpy的nonzero函数,该函数返回输入数组中所有非零元素的索引:
6rqinv9w2#
这个怎么样?
np.argmax()
在第一个True
值处停止,因此这可能会解决您不想迭代整个数组的问题?lf5gs5x23#
基准测试结果
因此,我决定在一个典型案例中比较所提出的解决方案。这三种方法是:
注意:
@timeit
是一个定制的 Package 器,我必须测量函数的执行时间。除了它是否完美的问题外,它对所有函数都是一样的,所以它应该是一个公平的比较。下面是在循环中执行它们的代码:
研究结果如下:
因此,在这个场景中,
argmax
解决方案显然是赢家,而generator
显然是输家。然而,我注意到第一个和最后一个索引所在的depth
(在这个例子中最多为N/10)可能会产生重大影响。在我的例子中,合理的值是depth=10000
(甚至更小)。因此,如果我重复这个实验,我会得到:depth = 10000
如您所见,在本例中,
generator
产生了更好的结果,如果depth
可以绑定到更小的数,则改进会更大。例如,参见:
depth=1000
depth=1000
哇,这是一个巨大的改进!当N = 2^20和2^25时,分别比numpy的
argmax
快了~6倍和~350倍。因此,在适当的情况下,不应该低估for循环/生成器的能力。最后,为了给kalszo的
nonzero
解决方案留下一句好话,我确实发现了它优于其他解决方案的一种情况,那就是除了两个位置(要查找的位置)之外,数组到处都是False
。因此,更改行:
depth=N//10
,只有两个真值并且具有较浅的深度:
depth=10000
,只有两个真值depth=10000
,只有两个真值depth=1000
,只有两个真值相对于阵列大小的小深度再次是有利于生成器表达式的关键因素。
总之,正确的解决方案在很大程度上取决于场景。对于我的特定情况,其中:
生成器表达式具有最好的性能,具有高达一个或两个数量级。