使用最后的非零值填充1d numpy数组的零值

mga*_*gab 11 python numpy

假设我们有一个填充了一些int值的1d numpy数组.让我们说其中一些是0.

有没有办法,使用numpy数组的功能,0用找到的最后一个非零值填充所有值?

例如:

arr = np.array([1, 0, 0, 2, 0, 4, 6, 8, 0, 0, 0, 0, 2])
fill_zeros_with_last(arr)
print arr

[1 1 1 2 2 4 6 8 8 8 8 8 2]
Run Code Online (Sandbox Code Playgroud)

一种方法是使用此功能:

def fill_zeros_with_last(arr):
    last_val = None # I don't really care about the initial value
    for i in range(arr.size):
        if arr[i]:
            last_val = arr[i]
        elif last_val is not None:
            arr[i] = last_val
Run Code Online (Sandbox Code Playgroud)

但是,这是使用原始python for循环而不是利用numpyscipy电源.

如果我们知道可以使用相当少量的连续零,我们可以使用基于的东西numpy.roll.问题是连续零的数量可能很大......

有任何想法吗?还是我们应该直接去Cython

免责声明:

我会说很久以前我在stackoverflow中发现了一个问题,问这样或类似的东西.我无法找到它.:-(

也许我错过了正确的搜索条件,抱歉副本.也许这只是我的想象......

jme*_*jme 18

这是一个解决方案np.maximum.accumulate:

def fill_zeros_with_last(arr):
    prev = np.arange(len(arr))
    prev[arr == 0] = 0
    prev = np.maximum.accumulate(prev)
    return arr[prev]
Run Code Online (Sandbox Code Playgroud)

我们构造一个数组prev,它具有相同的长度arr,并且这prev[i]是在第i个条目之前的最后一个非零条目的索引arr.例如,如果:

>>> arr = np.array([1, 0, 0, 2, 0, 4, 6, 8, 0, 0, 0, 0, 2])
Run Code Online (Sandbox Code Playgroud)

然后prev看起来像:

array([ 0,  0,  0,  3,  3,  5,  6,  7,  7,  7,  7,  7, 12])
Run Code Online (Sandbox Code Playgroud)

然后我们只是索引到arr,prev我们获得我们的结果.一个测试:

>>> arr = np.array([1, 0, 0, 2, 0, 4, 6, 8, 0, 0, 0, 0, 2])
>>> fill_zeros_with_last(arr)
array([1, 1, 1, 2, 2, 4, 6, 8, 8, 8, 8, 8, 2])
Run Code Online (Sandbox Code Playgroud)

注意:当数组的第一个条目为零时,请小心理解这是做什么的:

>>> fill_zeros_with_last(np.array([0,0,1,0,0]))
array([0, 0, 1, 1, 1])
Run Code Online (Sandbox Code Playgroud)


mga*_*gab 5

受到jme的回答和Bas Swinckels(在链接的问题中)的启发,我想出了 numpy 函数的不同组合:

def fill_zeros_with_last(arr, initial=0):
     ind = np.nonzero(arr)[0]
     cnt = np.cumsum(np.array(arr, dtype=bool))
     return np.where(cnt, arr[ind[cnt-1]], initial)
Run Code Online (Sandbox Code Playgroud)

我认为它很简洁,也很有效,所以我将其发布在这里以供记录。尽管如此,jme也简洁且易于理解,而且似乎更快,所以我接受它:-)