2017-02-09 91 views
1

鑑於以下數據框:逐行數據幀分割

df = pd.DataFrame(data={'item': [1, 2, 3, 4], 'start':[0.0, 2.0, 8.0, 6.0], 
          'end': [2.0, 6.0, 8.0, 14.0]}) 

如何快速通過分段間隔「開始」擴大上述數據幀逐行 - 「端」爲2的倍數?

對於上面的例子,所產生的數據幀應該是

Out= 
     item start end  
     1  0.0  2.0 
     2  2.0  4.0 
     2  4.0  6.0 
     3  8.0  8.0 
     4  6.0  8.0 
     4  8.0  10.0 
     4  10.0 12.0 
     4  12.0 14.0 

性能是最重要的對我來說,因爲我有幾百萬行的檢查。 我已經使用布爾索引爲那些不需要分段的行過濾整個數據幀。這是一個很快的速度然而,在其餘的行中,我應用了一個'for循環',並且創建了正確長度的數據框,我一直在追加。不幸的是,數百萬行的性能不足。

期待專家的解決方案!

回答

0

開始從原來的數據框中:

import pandas as pd 
    import numpy as np 
    df = pd.DataFrame(data={'item': [1, 2, 3, 4], 'start':[0.0, 2.0, 8.0, 6.0], 
          'end': [2.0, 6.0, 10.0, 14.0]}) 

然後,運行下面的代碼:

lengths = pd.Series([1, 2, 1, 4]) # For the example, I just created this array, 
             # but obviously I would use the mod function to 
             # determine the number of segments to create 

    # Row below elongates the dataframe according to the array 'lengths' 

    df = df.reindex(np.repeat(df.index.values, lengths), method='ffill') 
    df['start'] += pd.Series(df.groupby(level=0).cumcount()*2.0) 
    df['end'] = df['start'] + 2.0 
    print df 

注意初始數據幀包含一個錯誤。項目'3'需要'start = 8.0'和'end = 10.0'。

由於使用了熊貓Cython函數,我相信這種方法非常快捷。當然,還有其他的可能性。

0

您可以編寫一個函數,該函數返回展開的開始和結束時間的DataFrame。在這個例子中,我group,因爲我不知道你可以返回一個DataFrame從apply沒有它首先分組。

def convert(row): 
    start = row.start.values[0] 
    end = row.end.values[0] 
    if start == end: 
     return pd.DataFrame([[start, end]], columns=['start', 'end']) 
    else: 
     return pd.DataFrame({'start': np.arange(start, end, 2), 
          'end':np.arange(start + 2, end + 2, 2)}, 
          columns=['start', 'end']) 

df1=df.groupby('item').apply(convert) 
df1.index = df1.index.droplevel(1) 
df1.reset_index() 

    item start end 
0  1 0.0 2.0 
1  2 2.0 4.0 
2  2 4.0 6.0 
3  3 8.0 8.0 
4  4 6.0 8.0 
5  4 8.0 10.0 
6  4 10.0 12.0 
7  4 12.0 14.0 
+0

謝謝。我之前做過類似的事情。我發佈了一個我認爲更快的替代解決方案。 –