Python 用最后一个非零值填充1d numpy数组的零值

Python 用最后一个非零值填充1d numpy数组的零值,python,numpy,Python,Numpy,假设我们有一个1d numpy数组,其中填充了一些int值。假设其中一些是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): la

假设我们有一个1d numpy数组,其中填充了一些
int
值。假设其中一些是
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
循环,而不是利用
numpy
scipy
的强大功能

如果我们知道一个合理数量的连续零是可能的,我们可以使用基于
numpy.roll
的东西。问题是连续零的数量可能很大

有什么想法吗?或者我们应该直接去西顿吗

免责声明: 我想说很久以前,我在stackoverflow中发现了一个问题,问了一些类似的问题。我没能找到它-(


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

这里有一个使用
np.max.accumulate的解决方案:

def fill_zeros_with_last(arr):
    prev = np.arange(len(arr))
    prev[arr == 0] = 0
    prev = np.maximum.accumulate(prev)
    return arr[prev]
我们构造了一个数组
prev
,其长度与
arr
相同,并且
prev[i]
arr
第i个条目之前最后一个非零条目的索引。例如,如果:

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

下面是一个使用
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]
我们构造了一个数组
prev
,其长度与
arr
相同,并且
prev[i]
arr
第i个条目之前最后一个非零条目的索引。例如,如果:

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

如果
0
s仅以1的字符串形式出现,则
非零的使用可能会起作用:

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的字符串较长,则最好查找这些字符串并将其作为块处理。但如果大多数字符串较短,则此重复应用程序可能是最快的路径。

如果
0
s的字符串仅为1,则使用
非零
可能有效:

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的字符串很长,则最好查找这些字符串并将其作为块处理。但如果大多数字符串都很短,则此重复应用程序可能是最快的方法。

受的启发,我提出了不同的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)
我认为它很简洁,也很有效,所以我把它发布在这里记录在案。不过,'s也很简洁,容易理解,而且似乎更快,所以我接受了它:-)

受的启发,我在这里和(在链接的问题中)提出了一个不同的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)

我认为它很简洁,也很有效,所以我把它贴在这里记录在案。尽管如此,“s”还是简洁易懂,而且似乎速度更快,所以我接受它:-)

如果您不介意使用
pandas
,请看一下
ffill
方法(或者查看
fillna
了解完整的故事)。然而,numpy中没有内置“向前填充”类型的功能。正如@JoeKington所提到的,pandas中的
fillna
可以做到这一点。Cython源是
pad\u 2d\u inplace\u
函数,特别是底部的内环。代码正是您在示例中编写的。@JoeKington谢谢!功能不错!尽管如此,我还是希望避免依赖于
pandas
。如果您不介意使用
pandas
,请查看
ffill
方法(或参阅
fillna
了解完整的故事)。然而,numpy中没有内置“向前填充”类型的功能。正如@JoeKington所提到的,pandas中的
fillna
可以做到这一点。Cython源是
pad\u 2d\u inplace\u
函数,特别是底部的内环。代码正是您在示例中编写的。@JoeKington谢谢!功能不错!不过,我还是不想依靠熊猫来解决这个问题……你的答案可能比我的快——除非我的就地操作可能会节省时间。我自己也试过一个,但这一个还是一样好,而且更快的。:)谢谢你的答案可能比我的答案快——除非我的就地操作可能会节省时间。我自己尝试了一个,但这一个至少同样好而且快。:)谢谢不幸的是,我确实预期可能会有许多连续的
0
。我想了些什么,但是for循环没有说服我…:-/不幸的是,我确实预期可能会有许多连续的
0
。我想了些什么,但是for循环没有说服我…:-/很不错的。。。还有一个潜在的解决方案是使用
np.repeat
,但要正确设置边界似乎有点困难。它可能也没有我们两个的快。非常好。。。还有一个潜在的解决方案是使用
np.repeat
,但要正确设置边界似乎有点困难。它可能也没有我们两个的速度快。