2016-02-29 82 views
2

我有一個超過一百萬個元素的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

回答

4

你可以嘗試先創建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

0

您可以從最後開始迭代。這將是一個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(); 
1

這是一個純粹的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 
0

那麼你可以使用一個簡單的循環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,但你沒有指定的終值可能會欺騙你...