2017-10-05 48 views
2

我正在遍歷Python數據框並發現它非常慢。我明白,在Pandas中,你試圖對所有東西進行矢量化,但在這種情況下,我特別需要迭代(或者如果可以矢量化,我不清楚如何去做)。如何在引用前一行時迭代熊貓數據框?

邏輯很簡單:您有兩列「A」和「B」以及結果列「信號」。如果A等於1,則將信號設置爲1.如果B等於1,則將信號設置爲0.否則,信號就是之前的信號。換句話說,列A是「開」信號,列B是「關」信號,並且「信號」表示狀態。

這是我的代碼:

def signals(indata): 
    numrows = len(indata) 
    data = pd.DataFrame(index= range(0,numrows)) 
    data['A'] = indata['A'] 
    data['B'] = indata['B'] 
    data['signal'] = 0 


    for i in range(1,numrows): 
     if data['A'].iloc[i] == 1: 
      data['signal'].iloc[i] = 1 
     elif data['B'].iloc[i] == 1: 
      data['signal'].iloc[i] = 0 
     else: 
      data['signal'].iloc[i] = data['signal'].iloc[i-1] 
    return data 

實施例的輸入/輸出:

indata = pd.DataFrame(index = range(0,10)) 
indata['A'] = [0, 1, 0, 0, 0, 0, 1, 0, 0, 0] 
indata['B'] = [1, 0, 0, 0, 1, 0, 0, 0, 1, 1] 

signals(indata) 

輸出:

A B signal 
0 0 1 0 
1 1 0 1 
2 0 0 1 
3 0 0 1 
4 0 1 0 
5 0 0 0 
6 1 0 1 
7 0 0 1 
8 0 1 0 
9 0 1 0 

這種簡單的邏輯需要我的電腦46秒上的數據幀運行2000行隨機生成的數據。這裏

回答

0

最簡單的回答我的問題是,同時通過它迭代不寫入數據幀。我在numpy中創建了一個零數組,然後在數組中完成了我的迭代邏輯。然後我將數組寫到我的數據框的列中。

def signals3(indata): 
    numrows = len(indata) 
    data = pd.DataFrame(index= range(0,numrows)) 

    data['A'] = indata['A'] 
    data['B'] = indata['B'] 
    out_signal = np.zeros(numrows) 

    for i in range(1,numrows): 
     if data['A'].iloc[i] == 1: 
      out_signal[i] = 1 
     elif data['B'].iloc[i] == 1: 
      out_signal[i] = 0 
     else: 
      out_signal[i] = out_signal[i-1] 


    data['signal'] = out_signal 

    return data 

論的2000列隨機數據的數據幀,這往往只需要43毫秒而不是46秒(〜1000倍更快)。

我也嘗試過一種變型,其中我將數據幀列A和B分配到系列,然後遍歷系列。這有點快(27毫秒)。但似乎大部分緩慢是寫入數據框的。

coldspeed和djk的答案都比我的解決方案(約4.5毫秒)更快,但實際上我可能只是通過系列迭代,即使這不是最優的。

2
df['signal'] = df.A.groupby((df.A != df.B).cumsum()).transform('head', 1) 

df 
    A B signal 
0 0 1  0 
1 1 0  1 
2 0 0  1 
3 0 0  1 
4 0 1  0 
5 0 0  0 
6 1 0  1 
7 0 0  1 
8 0 1  0 
9 0 1  0 

邏輯涉及將您串聯成基於AB之間的不平等組,每個組的值由A確定。

+0

觀察大熊貓如何處理這種邏輯門操作很有意思,我仍然認爲這是有效的。 –

+0

這真的很整齊,你能解釋一下它的工作原理嗎? – DJK

+0

這是一個有趣的解決方案,但我不能爲自己想出更多複雜迭​​代的邏輯。我真的只是尋找一種簡單的,容易複製的方式來減少這類問題的處理時間。 – karakumy

1

你不需要在所有的迭代你可以做一些布爾索引

#set condition for A 
indata.loc[indata.A == 1,'signal'] = 1 
#set condition for B 
indata.loc[indata.B == 1,'signal'] = 0 
#forward fill NaN values 
indata.signal.fillna(method='ffill',inplace=True) 
相關問題