2017-09-04 211 views
1

我有熊貓數據框中的時間序列。時間戳可能不均勻(每1-5分鐘一次),但每隔5分鐘總會有一次(分鐘以0,5,10,15,20,25,30,35,40,45,50結尾的時間戳,55)。Python - 時間加權平均熊貓,按時間間隔分組

例子:

2017-01-01 2:05:00 32.90 
2017-01-01 2:07:30 29.83 
2017-01-01 2:10:00 45.76 
2017-01-01 2:15:00 16.22 
2017-01-01 2:20:00 17.33 
2017-01-01 2:25:00 23.40 
2017-01-01 2:28:45 150.12 
2017-01-01 2:30:00 100.29 
2017-01-01 2:35:00 38.45 
2017-01-01 2:40:00 67.12 
2017-01-01 2:45:00 20.00 
2017-01-01 2:50:00 58.41 
2017-01-01 2:55:00 58.32 
2017-01-01 3:00:00 59.89 

我想15分鐘塊的時間加權平均值。具有時間戳直接是在15分鐘標記(時間戳與結束0,15,30,45分鐘)結束的時間間隔中的行,所以分組如下:

Group 1 (interval 2017-01-01 2:00:00): 
    2017-01-01 2:05:00 32.90 
    2017-01-01 2:07:30 29.83 
    2017-01-01 2:10:00 45.76 
    2017-01-01 2:15:00 16.22 

Group 2 (interval 2017-01-01 2:15:00): 
    2017-01-01 2:20:00 17.33 
    2017-01-01 2:25:00 23.40 
    2017-01-01 2:28:45 150.12 
    2017-01-01 2:30:00 100.29 

Group 3 (interval 2017-01-01 2:30:00): 
    2017-01-01 2:35:00 38.45 
    2017-01-01 2:40:00 67.12 
    2017-01-01 2:45:00 20.00 

Group 4 (interval 2017-01-01 2:45:00): 
    2017-01-01 2:50:00 58.41 
    2017-01-01 2:55:00 58.32 
    2017-01-01 3:00:00 59.89 

平均必須是時間加權,所以不僅僅是一個組中所有值的標準平均值。

例如,組2的時間加權平均值不是72.785,這是所有4個值的常規平均值。相反,它應該是:

(5 minutes/15 minutes) * 17.33 = 5.776667  ==> The 5 minutes is taken from the difference between this timestamp and the previous timestamp 
+(5 minutes/15 minutes) * 23.40 = 7.8 
+(3.75 minutes/15 minutes) * 150.12 = 37.53 
+(1.25 minutes/15 minutes) * 100.29 = 8.3575 

= **59.46417** 

而且理想情況下,15分鐘參數,因爲這可能會在未來的60分鐘(每小時)改變,但我不認爲這是一個問題在這裏。

此外,性能在此非常重要。由於我的數據集將有大約10k行,因此逐個遍歷每條記錄會非常緩慢。

我試過尋找熊貓的df.rolling()函數,但無法弄清楚如何將它直接應用到我的特定場景。

非常感謝您的幫助!

更新1:

繼西蒙的輝煌的解決方案,我修改了它一點點。

我做了一些調整,它以使其適應我的具體情況:

def func(df): 
    if df.size == 0: return 
    timestep = 15*60 
    indexes = df.index - (df.index[-1] - pd.Timedelta(seconds=timestep)) 
    seconds = indexes.seconds 
    weight = [seconds[n]/timestep if n == 0 else (seconds[n] - seconds[n - 1])/timestep 
      for n, k in enumerate(seconds)] 
    return np.sum(weight*df.values) 

這是爲了應付可能是空的,每隔15分鐘(中缺少DB行)

回答

3

這一次是棘手。我希望看到另一位評論者更有效地做到這一點,因爲我有預感,有更好的方法來做到這一點。

我也跳過了一個部分,它參數化了15分鐘的值,但我指出你可以在評論中做到這一點。這留給讀者一個練習:D它應該被參數化,因爲它現在有很多隨機的'* 15'和'* 60'值散佈在這個地方,看起來很笨拙。

我也很累,我的妻子想看電影,所以我沒有清理我的代碼。這有點混亂,應該寫得更清潔 - 這可能或不值得做,取決於其他人是否可以在6行代碼中重做這些。如果明天早上它還沒有回答,我會回過頭來,做得更好。

更新更好的解決方案1 ​​

def func(df): 
    timestep = 15*60 
    seconds = (df.index.minute*60+df.index.second)-timestep 
    weight = [k/timestep if n == 0 else (seconds[n] - seconds[n - 1])/timestep 
       for n, k in enumerate(seconds)] 
    return np.sum(weight*df.values) 

df.resample('15min', closed='right').apply(func) 
+0

這是輝煌!非常感謝,這正是我需要的! 有沒有辦法使用GroupBy()而不是Resample()? 原因是我有另一列我想分組,其中我沒有包括在原來的問題,爲簡單起見。我似乎是使用表: df.groupby([pd.TimeGrouper(freq ='15Min')])) 但似乎沒有辦法關閉右側的組,如resample()函數具有。 –

+0

所以基本上,我有以下的4列在我的表: 「TIME | ZONE |價格1 | PRICE2」 我想有每個區的時間加權平均每十五分鐘間隔每個價格 –

+0

我做一些更多的數據測試和整個事情是非常緩慢的;也許我只是不習慣Python的速度。要處理160萬行(每組約3行530k組),大約需要10分鐘。我在C#程序中做了同樣的事情(代碼長得多,因爲我不得不在每一行上手動迭代),並且花了不到10秒。 –