改变numpy数组中的元素

8

我有一个numpy数组:

a = [3., 0., 4., 2., 0., 0., 0.]

我希望创建一个新的数组,使其中非零元素转换为0,并将零元素转换为一个数字,该数字等于连续零元素的数量,即:

b = [0., 0., 0., 1., 0., 0., 0., 0., 0., 0., 3.]

寻找矢量化的方法来处理此操作,因为数组将具有超过100万个元素。 非常感谢任何帮助。


如果这个可以向量化,我会感到惊讶,但祝你好运 :) - Hammer
2个回答

8

这应该会起到作用,大致上的实现方式是:1)找到所有连续的零并计数;2)计算输出数组的大小并初始化为零;3)将第一部分的计数放置在正确的位置。

def cz(a):
    a = np.asarray(a, int)

    # Find where sequences of zeros start and end
    wz = np.zeros(len(a) + 2, dtype=bool)
    wz[1:-1] = a == 0
    change = wz[1:] != wz[:-1]
    edges = np.where(change)[0]
    # Take the difference to get the number of zeros in each sequence
    consecutive_zeros = edges[1::2] - edges[::2]

    # Figure out where to put consecutive_zeros
    idx = a.cumsum()
    n = idx[-1] if len(idx) > 0 else 0
    idx = idx[edges[::2]]
    idx += np.arange(len(idx))

    # Create output array and populate with values for consecutive_zeros
    out = np.zeros(len(consecutive_zeros) + n)
    out[idx] = consecutive_zeros
    return out

非常出色,运行得非常好。比我尝试使用的循环快了几个数量级。 - tommw

4

针对多样性的解决方案:

a = np.array([3., 0., 4., 2., 0., 0., 0.],dtype=np.int)

inds = np.cumsum(a)

#Find first occurrences and values thereof.
uvals,zero_pos = np.unique(inds,return_index=True)
zero_pos = np.hstack((zero_pos,a.shape[0]))+1

#Gets zero lengths
values =  np.diff(zero_pos)-1
mask = (uvals!=0)

#Ignore where we have consecutive values
zero_inds = uvals[mask]
zero_inds += np.arange(zero_inds.shape[0])

#Create output array and apply zero values
out = np.zeros(inds[-1] + zero_inds.shape[0])
out[zero_inds] = values[mask]

out
[ 0.  0.  0.  1.  0.  0.  0.  0.  0.  0.  3.]

主要区别在于,只要数组单调递增,我们可以使用np.unique查找数组的第一次出现。


不错的答案。如果a有前导0,那可能差了一点,但应该很容易修复。 - Bi Rico
两者都不错,@BiRico的在我的机器上还是稍微快一点。 - askewchan
@BiRico 不错的观点,它确实缺乏这个方面。有趣的是,在你的a数组中需要大的值(a>300),才能使这种方法变得更快。 - Daniel

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接