2014-11-21 44 views
11

總和假設我有數據幀下面大熊貓軋製的最後五分鐘

Date, A 
2014-11-21 11:00:00, 1 
2014-11-21 11:03:00, 4 
2014-11-21 11:04:00, 1 
2014-11-21 11:05:00, 2 
2014-11-21 11:07:00, 4 
2014-11-21 11:08:00, 1 
2014-11-21 11:12:00, 1 
2014-11-21 11:13:00, 2 

第一列是日期時間對象和第二列是一個整數。我想要的是計算每行最後五分鐘的列'A'的總和。

作爲行2014-11-21 11:12:00, 1的示例,列'A'的總和將是2(1 + 1),並且行'012'的總和爲7(2 + 1 + 4)。重要的是,時間窗口(5分鐘)的過去行數對於每一行都不相同(因爲時間序列是不規則的)。

如何使用pandas中的rolling_sum方法獲得列「A」的最後五分鐘的總和?提前致謝。

回答

13

在一般情況下,如果日期是完全隨意的,我想你將不得不在行或use df.apply,使用Python的for-loop(其中引擎蓋下,還使用了Python的循環。)

然而,如果您的日期與上述情況共用同一頻率,則應該比使用df.apply快得多:根據常見頻率擴展時間序列 - 在這種情況下爲1分鐘 - 填寫NaNs用零點,然後撥打rolling_sum

In [279]: pd.rolling_sum(df.set_index(['Date']).asfreq('1T').fillna(0), window=5, min_periods=1).reindex(df['Date']) 
Out[279]: 
         A 
Date     
2014-11-21 11:00:00 1 
2014-11-21 11:03:00 5 
2014-11-21 11:04:00 6 
2014-11-21 11:05:00 7 
2014-11-21 11:07:00 11 
2014-11-21 11:08:00 8 
2014-11-21 11:12:00 2 
2014-11-21 11:13:00 3 

當然,如果您願意接受足夠小的粒度,則任何時間序列都有一個共同的頻率,但所需的尺寸df.asfreq(...)可能會使此技巧不切實際。


以下是使用df.apply的更一般方法的示例。請注意,致電searchsorted依賴df['Date']排序。

import numpy as np 
import pandas as pd 
df = pd.read_csv('data', parse_dates=[0], sep=',\s*') 
start_dates = df['Date'] - pd.Timedelta(minutes=5) 
df['start_index'] = df['Date'].values.searchsorted(start_dates, side='right') 
df['end_index'] = np.arange(len(df)) 

def sum_window(row): 
    return df['A'].iloc[row['start_index']:row['end_index']+1].sum() 
df['rolling_sum'] = df.apply(sum_window, axis=1) 

print(df[['Date', 'A', 'rolling_sum']]) 

產生

    Date A rolling_sum 
0 2014-11-21 11:00:00 1   1 
1 2014-11-21 11:03:00 4   5 
2 2014-11-21 11:04:00 1   6 
3 2014-11-21 11:05:00 2   7 
4 2014-11-21 11:07:00 4   11 
5 2014-11-21 11:08:00 1   8 
6 2014-11-21 11:12:00 1   2 
7 2014-11-21 11:13:00 2   3 

這裏是df.asfreq招比較與調用df.apply基準:

import numpy as np 
import pandas as pd 
df = pd.read_csv('data', parse_dates=[0], sep=',\s*') 

def big_df(df): 
    df = df.copy() 
    for i in range(7): 
     dates = df['Date'] + pd.Timedelta(df.iloc[-1]['Date']-df.iloc[0]['Date']) + pd.Timedelta('1 minute') 
     df2 = pd.DataFrame({'Date': dates, 'A': df['A']}) 
     df = pd.concat([df, df2]) 
    df = df.reset_index(drop=True) 
    return df 

def using_apply(): 
    start_dates = df['Date'] - pd.Timedelta(minutes=5) 
    df['start_index'] = df['Date'].values.searchsorted(start_dates, side='right') 
    df['end_index'] = np.arange(len(df)) 

    def sum_window(row): 
     return df['A'].iloc[row['start_index']:row['end_index']+1].sum() 

    df['rolling_sum'] = df.apply(sum_window, axis=1) 
    return df[['Date', 'rolling_sum']] 

def using_asfreq(): 
    result = (pd.rolling_sum(
     df.set_index(['Date']).asfreq('1T').fillna(0), 
     window=5, min_periods=1).reindex(df['Date'])) 
    return result 

In [364]: df = big_df(df) 

In [367]: %timeit using_asfreq() 
1000 loops, best of 3: 1.21 ms per loop 

In [368]: %timeit using_apply() 
1 loops, best of 3: 208 ms per loop 
+0

非常感謝您的快速回答。我不能使用df.asfreq(...)方法,因爲我的數據集中的最小粒度是秒,而且有數百萬行。但是df.apply方法可以解決這個問題。 – 2014-11-24 09:07:19

+0

一般的方法是有效的,如果在長代碼中使用它,只需記住一件事:函數'sum_window'沒有明確使用輸入'df',所以需要小心。 – nilesh 2017-06-09 05:07:47