2017-05-29 11 views
2

2つの列でグループ化されたデータフレームに繰り返し機能を適用したいと思います。具体的には、単純にintではなくdatetime値として "freq"と "window"の両方を使用します。複数の列でグループにローリング機能を適用する

原則として、私はHow to apply rolling functions in a group by object in pandaspandas rolling sum of last five minutesのメソッドを組み合わせようとしています。我々はいくつかのIDを期待するが、ここで入力

は、1つのID = 33で、データのサンプルです。

X = [{'date': '2017-02-05', 'id': 33, 'item': 'A', 'points': 20}, 
{'date': '2017-02-05', 'id': 33, 'item': 'B', 'points': 10}, 
{'date': '2017-02-06', 'id': 33, 'item': 'B', 'points': 10}, 
{'date': '2017-02-11', 'id': 33, 'item': 'A', 'points': 1}, 
{'date': '2017-02-11', 'id': 33, 'item': 'A', 'points': 1}, 
{'date': '2017-02-11', 'id': 33, 'item': 'A', 'points': 1}, 
{'date': '2017-02-13', 'id': 33, 'item': 'A', 'points': 4}] 

# df = pd.DataFrame(X) and reindex df to pd.to_datetime(df['date']) 

df 

      id item points 
date      
2017-02-05 33 A  20 
2017-02-05 33 B  10 
2017-02-06 33 B  10 
2017-02-11 33 A  1 
2017-02-11 33 A  1 
2017-02-11 33 A  1 
2017-02-13 33 A  4 

目標

サンプルそれぞれ 'ID' ごとに2日(FREQ = '2D')と過去3日間(ウィンドウ= '3D' 上に各項目の合計点の合計を返します)、終了日を含め

所望の出力

  id A B 
date      
2017-02-05 33 20 10 
2017-02-07 33 20 30  
2017-02-09 33 0 10 
2017-02-11 33 3 0 
2017-02-13 33 7 0 

例:右端を含む2017-02-13の最終日に、2017-02-11から2017-02-13までの3日間をサンプリングします。この期間では、ID = 33が試み

pd.rolling_sumとGROUPBYの試み次のようには機能しなかった1 + 1 + 1 + 4 = 7

に等しいポイントの合計を持っていました、繰り返し日付

df.groupby(['id', 'item'])['points'].apply(pd.rolling_sum, freq='4D', window=3) ValueError: cannot reindex from a duplicate axis 

のためにもドキュメントhttp://pandas.pydata.org/pandas-docs/version/0.17.0/generated/pandas.rolling_apply.html「窓」からサイズのサンプル期間を表すint、ないサンプリングする日数であることに注意してください。

またdf_idを選択し、一意のIDのIDの上にループを設定し、しかし3日の所望のルックバックはもちろん

df.groupby(['id', 'item'])['points'].resample('2D', label='right', closed='right').\ 
apply(lambda x: x.last('3D').sum()) 

id item date  
33 A  2017-02-05 20 
      2017-02-07  0 
      2017-02-09  0 
      2017-02-11  3 
      2017-02-13  4 
    B  2017-02-05 10 
      2017-02-07 10 

を使用していないよう、最後にリサンプリングして使ってみてくださいすることができます= df [df ['id'] == ID]となり、期間の合計は機能しますが、計算量が多く、groupbyの素敵なベクトル化を利用しません。ここ

おかげで良い提案を@jezraelするこれまで

ノート

パンダバージョン= 0.20.1

私は(ローリング上の理由ドキュメントへのわずか混乱しています) :https://pandas.pydata.org/pandas-docs/stable/generated/pandas.DataFrame.rolling.html は、 "window"パラメータがintまたはoffsetにあるが、df.rolling(window = '3D'、...)を試みていることを示唆しているraise ValueError("window must be an integer") 上記のドキュメントは、最新のc ./core/windowからローリングのウィンドウのためのode。PY: https://github.com/pandas-dev/pandas/blob/master/pandas/core/window.py

elif not is_integer(self.window): 
      raise ValueError("window must be an integer") 

答えて

2
  • 私たちは、単一レベルのdatetimeインデックスを持っている場合、日付周波数でresamplerollingを処理するのが最も簡単です。
  • しかし、私はA/B重複を扱うことなく、適切にpivot/unstackすることはできませんので、私groupbysum
  • I unstack 1レベルdateので、私はfill_value=0をすることができますよ。現在、私はunstackを一度に複数レベルにすると、fill_value=0を入力できません。私は今、私は、インデックス内の単一のレベルを持っていることを、私は最後に、私は3ローリングん
  • インデックスに最大値に最小の日付範囲でインデックスを再作成転置T
  • でそれを補います2日おきに結果を再集計します。resample
  • 名前を変更する指標ともう1つのピボットを使用してこれをクリーンアップします。説明のため

s = df.set_index(['id', 'item'], append=True).points 
s = s.groupby(level=['date', 'id', 'item']).sum() 

d = s.unstack('date', fill_value=0).T 
tidx = pd.date_range(d.index.min(), d.index.max()) 
d = d.reindex(tidx, fill_value=0) 

d1 = d.rolling('3D').sum().resample('2D').first().astype(d.dtypes).stack(0) 
d1 = d1.rename_axis(['date', 'id']).rename_axis(None, 1) 
print(d1) 

       A B 
date  id   
2017-02-05 33 20 10 
2017-02-07 33 20 20 
2017-02-09 33 0 0 
2017-02-11 33 3 0 
2017-02-13 33 7 0 
+0

感謝。ローリング方法で日付/時刻値にアクセスする際のヒント(たとえば、特定のウィンドウで最も最近ゼロでないエントリの時間)現時点では、浮動小数点数の配列だけがd.rolling( '3D')のような呼び出しでアクセスできるようです。apply(lambda X:func(X))。resample( '2D') – Quetzalcoatl

+0

別の質問。このヒントは 'np.nan'としてゼロをマスクした後に' pd.Series.first_valid_index'または 'pd.Series.last_valid_index'を使うことです。あなたは 'numpy'でも他のやり方をすることができます。 – piRSquared

0
df = pd.DataFrame(X) 

# group sum by day 
df = df.groupby(['date', 'id', 'item'])['points'].sum().reset_index().sort_values(['date', 'id', 'item']) 

# convert index to datetime index 
df = df.set_index('date') 
df.index = DatetimeIndex(df.index) 

# rolloing sum by 3D 
df['pointsum'] = df.groupby(['id', 'item']).transform(lambda x: x.rolling(window='3D').sum()) 

# reshape dataframe 
df = df.reset_index().set_index(['date', 'id', 'item'])['pointsum'].unstack().reset_index().set_index('date').fillna(0) 

df 
+0

これは '2D'サンプリング周波数に対応していないようです。 – Quetzalcoatl

+0

「x.rolling(window = '3D')」で追加できますか?サンプルデータは、全体の質問を理解するにはあまりにも少ないです。 – xmduhan

+0

piRsquaredの答えを参照してください:-) – Quetzalcoatl

関連する問題