2017-10-06 5 views
1

私は30日の時系列のウィンドウにリサンプリングしたい以下の一般的な形式でデータを持っている:PythonのPANDAS:リサンプリング多変量時系列GROUPBY

'customer_id','transaction_dt','product','price','units' 
1,2004-01-02,thing1,25,47 
1,2004-01-17,thing2,150,8 
2,2004-01-29,thing2,150,25 
3,2017-07-15,thing3,55,17 
3,2016-05-12,thing3,55,47 
4,2012-02-23,thing2,150,22 
4,2009-10-10,thing1,25,12 
4,2014-04-04,thing2,150,2 
5,2008-07-09,thing2,150,43 

私が開始する30日のウィンドウをしたいと思います2014-01-01に終了し、12-31-2018に終了します。すべての顧客がすべてのウィンドウにレコードを持つことは保証されません。顧客がウィンドウ内に複数のトランザクションを持つ場合、価格の加重平均をとり、単位を合計し、製品名を連結して、ウィンドウごとに顧客ごとに1レコードを作成します。誰もがこの問題にアプローチするためにいくつかのより良い方法を知っている

wa = lambda x:np.average(x, weights=df.loc[x.index, 'units']) 
con = lambda x: '/'.join(x)) 

agg_funcs = {'customer_id':'first', 
      'product':'con', 
      'price':'wa', 
      'transaction_dt':'first', 
      'units':'sum'} 

df_window = df.groupby(['customer_id', pd.Grouper(freq='30D')]).agg(agg_funcs) 
df_window_final = df_window.unstack('customer_id', fill_value=0) 

場合、私はそれをお願い申し上げます(特にインプレースおよび/またはベクトル化法で):私はこれまで持って何

はこのようなものです。理想的には、ウィンドウの開始日と終了日を列として列に追加することもできます。

最終的な出力は、理想的には次のようになります。

'customer_id','transaction_dt','product','price','units','window_start_dt','window_end_dt' 
1,2004-01-02,thing1/thing2,(weighted average price),(total units),(window_start_dt),(window_end_dt) 
2,2004-01-29,thing2,(weighted average price),(total units),(window_start_dt),(window_end_dt) 
3,2017-07-15,thing3,(weighted average price),(total units),(window_start_dt),(window_end_dt) 
3,2016-05-12,thing3,(weighted average price),(total units),(window_start_dt),(window_end_dt) 
4,2012-02-23,thing2,(weighted average price),(total units),(window_start_dt),(window_end_dt) 
4,2009-10-10,thing1,(weighted average price),(total units),(window_start_dt),(window_end_dt) 
4,2014-04-04,thing2,(weighted average price),(total units),(window_start_dt),(window_end_dt) 
5,2008-07-09,thing2,(weighted average price),(total units),(window_start_dt),(window_end_dt) 
+0

加重平均価格と平均との重みを必要とします。体重は何ですか?そして、あいまいさがないように、最終的な結果はどのように見えますか。そうすれば、助けを決める人は答えを出す前に何かを比較することができます。 – piRSquared

+0

申し訳ありませんが混乱している場合は、groupby中のウィンドウ内のユニットの総数から加重平均価格を計算することになっています。wa = lambda x:np.average(x、weights = df.loc [x.index 、 'units']) – Pylander

+0

価格の重さは(単位)です。 – Pylander

答えて

1

編集新しいソリューションのために。私はtransaction_dtを30日間の期間オブジェクトに変換してグループ化することができると思います。

p = pd.period_range('2004-1-1', '12-31-2018',freq='30D') 
def find_period(v): 
    p_idx = np.argmax(v < p.end_time) 
    return p[p_idx] 
df['period'] = df['transaction_dt'].apply(find_period) 
df 

    customer_id transaction_dt product price units  period 
0   1  2004-01-02 thing1  25  47 2004-01-01 
1   1  2004-01-17 thing2 150  8 2004-01-01 
2   2  2004-01-29 thing2 150  25 2004-01-01 
3   3  2017-07-15 thing3  55  17 2017-06-21 
4   3  2016-05-12 thing3  55  47 2016-04-27 
5   4  2012-02-23 thing2 150  22 2012-02-18 
6   4  2009-10-10 thing1  25  12 2009-10-01 
7   4  2014-04-04 thing2 150  2 2014-03-09 
8   5  2008-07-09 thing2 150  43 2008-07-08 

このデータフレームを使用して、製品の連結、価格の加重平均、および単位の合計を取得できるようになりました。その後、期間機能を使用して終了時間を取得します。

def my_funcs(df): 
    data = {} 
    data['product'] = '/'.join(df['product'].tolist()) 
    data['units'] = df.units.sum() 
    data['price'] = np.average(df['price'], weights=df['units']) 
    data['transaction_dt'] = df['transaction_dt'].iloc[0] 
    data['window_start_time'] = df['period'].iloc[0].start_time 
    data['window_end_time'] = df['period'].iloc[0].end_time 
    return pd.Series(data, index=['transaction_dt', 'product', 'price','units', 
            'window_start_time', 'window_end_time']) 

df.groupby(['customer_id', 'period']).apply(my_funcs).reset_index('period', drop=True) 

enter image description here

+0

これは非常にエレガントなソリューションです!ありがとうございました!読者には、新しい値を作成するために一連のgroupby/transformsを使用してアプローチを考え出しました。 – Pylander

+0

私はこれを最近もう一度見直しました。残念ながら、my_funcsの 'window_start_time'と 'window_end_time'が正しく動作するかどうかはわかりません。それは私のための最後の30日の窓の日付だけを返すようです。 – Pylander