2017-09-04 27 views
1

私はPandas DataFrameに時系列を持っています。タイムスタンプは不均等(1〜5分ごと)ですが、5分ごとに1つ(タイムスタンプは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分のブロックの時間加重平均値を取得したいです。

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 

平均でなければなりません:間隔の終了15分マーク(0,15,30,45で終わる分とタイムスタンプ)の上に直接あるので、次のようにグループ化されたタイムスタンプを持つ行時間加重値なので、グループ内のすべての値の標準平均値だけではありません。

たとえば、グループ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** 

また理想的には、これは60分(時間給)に将来的に変更される可能性がありますよう15分は、パラメータ化され、私は、これはここでの問題はないと思います。

また、パフォーマンスはこれで非常に重要です。私のデータセットは約10k行になるので、各レコードを1つずつ繰り返していくのはかなり遅いでしょう。

私はPandasのdf.rolling()関数を調べてみましたが、特定のシナリオに直接適用する方法を理解できませんでした。

ありがとうございました!

UPDATE 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) 

これは、この1だった空の可能性が15分間隔(DBで欠落行)

答えて

3

に対処することですトリッキー。私はこれを行うより良い方法があるのですから、別のコメント作成者がこれをもっと効率的にやってくれるのが大好きです。

また、15分の値をパラメータ化する1つの部分はスキップしましたが、コメントでどのように行うかを指摘します。これは読者のための練習として残されています: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

これは素晴らしいです!ありがとう、これは私が必要としていたものです! Resample()の代わりにGroupBy()を使用する方法はありますか? 理由は、グループ化したい別の列がありますが、単純化のために元の質問には含めませんでした。私は使用するテーブルのようです: df.groupby([pd.TimeGrouper(freq = '15Min')]) しかし、右側のグループを閉じる方法はないようですresample()関数が持っています。 –

+0

だから基本的に、私は私のテーブルに次の4列があります「| ZONE | PRICE1 | TIME PRICE2」 をそして私は私がした各価格 –

+0

ための時間加重ゾーンごとの平均値と15分間隔ごとを持ちたいですより多くのデータとより多くのテストは非常に遅いです。多分私はPythonの速度に慣れていないかもしれません。 160万行(~3行ずつの530kグループ)を処理するには、約10分かかりました。 C#プログラムでも同じことをしました(各行で手作業で反復しなければならないため、コードはずっと長くなりました)、10秒以下でした。 –

関連する問題