Python:如何在列表中设置零值/ array/pd.Series是下一个非零值?

问题描述:

我有一个超过一百万个元素的Python列表式结构。每个元素取三个可能的值中的一个,即-101。我试图实现的是用下一个非零值替换所有的零。Python:如何在列表中设置零值/ array/pd.Series是下一个非零值?

举例来说,如果我有

[1, 0, 0, -1, 0, 1, 0, 0, 0, -1] 
手术后

我得

[1 -1-1,-1,,1 -1-1,-1,-1]。

我可以有一个嵌套的循环结构来实现这个目标,但在列表中有超过100万个元素,它将永远运行。有没有人知道一个更快的算法,可以实现这个目标?

+0

你是否需要内存中的整个输出列表,或者生成器方法可以吗?你用什么做下游? – tzaman

你可以尝试先创建Series,然后replace0NaN和最后使用fillna

import pandas as pd 
import numpy as np 

li = [1, 0, 0, -1, 0, 1, 0, 0, 0, -1] 
s = pd.Series(li) 
print s 
0 1 
1 0 
2 0 
3 -1 
4 0 
5 1 
6 0 
7 0 
8 0 
9 -1 
dtype: int64 


print s.replace({0:np.nan}) 
0  1 
1 NaN 
2 NaN 
3 -1 
4 NaN 
5  1 
6 NaN 
7 NaN 
8 NaN 
9 -1 
dtype: float64 
print s.replace({0:np.nan}).fillna(method='bfill') 
0 1 
1 -1 
2 -1 
3 -1 
4 1 
5 1 
6 -1 
7 -1 
8 -1 
9 -1 
dtype: float64 

或替代replace使用loc,然后将其转换由astype和最后使用tolist为int:

s.loc[s == 0] = np.nan 

s.loc[s == 0] = np.nan 
print s.fillna(method='bfill').astype(int).tolist() 
[1, -1, -1, -1, 1, 1, -1, -1, -1, -1] 
+0

工程就像一个魅力。非常感谢! – Nero

您可以从最后开始迭代。这将是一个On)解决方案。

a=[0,1,0,0,0,0,-1,0]; 
length=len(a); 
length=length-1; 
//Assuming if last value is 0 you just let it be and the 0s before it. 
val=0; 
print a 
for i in range(length): 
    if (a[length-i] != 0): 
     val=a[length -i]; 
    else: 
     a[length-i]=val; 
    i=i+1; 
print a 
exit(); 

这是一个纯粹的Python解决方案。

创建一个保留先前值状态的小类,并将当前值与此先前值进行比较。

class Checker: 
    def _compare(self, val): 
     if val or not self.prior: 
      self.prior = val 
      return val 
     return self.prior 
    def reverse_fill_list(self, some_list): 
     self.prior = None 
     return [self._compare(v) for v in some_list[::-1]][::-1] 

然后以相反的顺序在列表中使用列表理解(使用[:: - 1]来反转)。然后再次反转结果以恢复原始订单。

some_list = [1, 0, 0, -1, 0, 1, 0, 0, 0, -1] 
c = Checker() # Instantiate object. 

>>> c.reverse_fill_list(some_list) 
[1, -1, -1, -1, 1, 1, -1, -1, -1, -1] 


np.random.seed(0) 
# Create one million values in range [-1, 0, 1]. 
a = np.random.random_integers(-1, 1, 1000000) 
>>> a[:10] 
array([-1, 0, -1, 0, 0, 1, -1, 1, -1, -1]) 

%timeit c.reverse_fill_list(a) 
1 loops, best of 3: 311 ms per loop 

使用熊猫(使用@Jezrael解决方案)的结果更快。

>>> pd.Series(a).replace({0:np.nan}).fillna(method='bfill').tolist() 
10 loops, best of 3: 136 ms per loop 

那么你可以使用一个简单的循环while如果你想纯Python:

li=[1, 0, 0, -1, 0, 1, 0, 0, 0, -1] 
i=len(li)-1 
while i: 
    if li[i]: 
     val=li[i] 
    else: 
     li[i]=val 
    i-=1  

>>> li 
[1, -1, -1, -1, 1, 1, -1, -1, -1, -1] 

假定最​​后一个值是1或-1,但你没有指定的终值可能会欺骗你...