将函数应用于numpy数组元素的有效方法?

问题描述

我有一个由布尔值w构成的巨大一维numpy数组和一个索引i不断增加的列表,这些列表将w分成len(i)+1个子数组。一个玩具示例是:

w=numpy.array([True,False,True,False])
i=numpy.array([0,2,5,8,8])

我希望计算一个numpy数组wi,如果第i个子数组包含一个i,则其第True个条目为1,否则为0。换句话说,i的第w个条目是i的第w个子数组的元素的和(逻辑“或”)。在我们的示例中,输出为:

[0 0 1 1 0 1 0 0]

这是通过以下代码实现的:

wi=numpy.fromiter(map(numpy.any,numpy.split(w,i)),int)

是否有更有效的方法做到这一点?或者就内存而言,这是否是最佳选择?

P.S。 related post

解决方法

让我们尝试np.add.reductat

wi = np.add.reduceat(w,np.r_[0,i]).astype(bool)

输出:

array([1,1,0])

性能:

%timeit -n 100 wi = np.add.reduceat(w,i]).astype(bool).astype(int)
21.7 µs ± 7.86 µs per loop (mean ± std. dev. of 7 runs,100 loops each)

%timeit -n 100 wi=np.fromiter(map(np.any,np.split(w,i)),int)
44.5 µs ± 7.79 µs per loop (mean ± std. dev. of 7 runs,100 loops each)

因此,我们这里的速度约为2倍。

,

为了提高效率(内存和性能),请使用np.bitwise_or.reduceat,因为它将输出保持为布尔值-

In [10]: np.bitwise_or.reduceat(w,i])
Out[10]: array([ True,True,False,False])

要具有int输出,请查看为int-

In [11]: np.bitwise_or.reduceat(w,i]).view('i1')
Out[11]: array([1,0],dtype=int8)

这是全天候解决方案-

def slice_reduce_or(w,i):
    valid = i<len(w)
    invalidc =( ~valid).sum()
    i = i[valid]
    
    mi = np.r_[i[:-1]!=i[1:],True]
    pp = i[mi]
    p1 = np.bitwise_or.reduceat(w,pp)
    
    N = len(i)+1
    out = np.zeros(N+invalidc,dtype=bool)
    out[1:N][mi] = p1
    out[0] = w[:i[0]].any()
    return out.view('i1')