我们假设我们有一个填充了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]
一种方法是使用此功能:
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
的内容。问题是连续零的数量可能很大......
有什么想法吗?或者我们应该直接进入Cython
?
我会说很久以前我在stackoverflow中发现了一个问题,问这样或类似的东西。我无法找到它。 : - (
也许我错过了正确的搜索字词,对不起那些副本。也许这只是我的想象......
答案 0 :(得分:16)
以下是使用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]
是 i之前的最后一个非零条目的索引 arr
的条目。例如,如果:
>>> 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])
然后我们只需使用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])
注意:当数组的第一个条目为零时,请小心理解这是做什么的:
>>> fill_zeros_with_last(np.array([0,0,1,0,0]))
array([0, 0, 1, 1, 1])
答案 1 :(得分:4)
受到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)
我认为它简洁而且有效,所以我将它张贴在这里作为记录。尽管如此,jme还简洁易懂,似乎更快,所以我接受它: - )
答案 2 :(得分:1)
如果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的字符串很长,那么查找这些字符串并将它们作为块处理可能会更好。但如果大多数字符串都很短,那么重复应用可能是最快的路径。