繁体   English   中英

用最后一个非零值填充一维 numpy 数组的零值

[英]Fill zero values of 1d numpy array with last non-zero values

假设我们有一个填充了一些int值的一维 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]

一种方法是使用此功能:

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

但是,这是使用原始 python for循环而不是利用numpyscipy功能。

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

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

免责声明:

我会说很久以前我在 stackoverflow 中发现了一个类似这样或非常相似的问题。 我无法找到它。 :-(

也许我错过了正确的搜索词,很抱歉重复。 或许只是我的错觉……

这是使用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]

我们构造了一个与arr长度相同的数组prev ,并且prev[i]arri个条目之前的最后一个非零条目的索引。 例如,如果:

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

然后prev看起来像:

array([ 0,  0,  0,  3,  3,  5,  6,  7,  7,  7,  7,  7, 12])

然后我们只用prev索引到arr ,我们就得到了我们的结果。 一个测试:

>>> 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])

注意:当数组的第一个条目为零时,请注意理解它的作用:

>>> fill_zeros_with_last(np.array([0,0,1,0,0]))
array([0, 0, 1, 1, 1])

jme在这里的回答和Bas Swinkels 的启发(在链接的问题中),我想出了一种不同的 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)

我认为它既简洁又有效,所以我将它张贴在这里以作记录。 尽管如此, jme也简洁易懂,而且速度似乎更快,所以我接受了:-)

如果0只出现在 1 的字符串中,则nonzero这种使用可能有效:

In [266]: arr=np.array([1,0,2,3,0,4,0,5])
In [267]: I=np.nonzero(arr==0)[0]
In [268]: arr[I] = arr[I-1]
In [269]: arr
Out[269]: array([1, 1, 2, 3, 3, 4, 4, 5])

我可以通过反复应用这个来处理你的arr ,直到I是空的。

In [286]: arr = np.array([1, 0, 0, 2, 0, 4, 6, 8, 0, 0, 0, 0, 2])

In [287]: while True:
   .....:     I=np.nonzero(arr==0)[0]
   .....:     if len(I)==0: break
   .....:     arr[I] = arr[I-1]
   .....:     

In [288]: arr
Out[288]: array([1, 1, 1, 2, 2, 4, 6, 8, 8, 8, 8, 8, 2])

如果 0 的字符串很长,最好查找这些字符串并将它们作为块处理。 但如果大多数字符串都很短,这种重复应用可能是最快的途径。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM