2016-11-23 34 views
3

ローリング時間加重移動平均、私は(それはそれの一部だし、実際のデータフレームを超える70K行で)顧客の販売履歴の次のデータフレームを持っている:パンダ:GROUPBY

import pandas as pd 
import datetime as DT 

df_test = pd.DataFrame({ 
    'Cus_ID': ["T313","T348","T313","T348","T313","T348","T329","T329","T348","T313","T329","T348"], 
    'Value': [3,2,3,4,5,3,7.25,10.25,4.5,11.75,6.25,6], 
    'Date' : [ 
     DT.datetime(2015,10,18), 
     DT.datetime(2015,11,14), 
     DT.datetime(2015,11,18), 
     DT.datetime(2015,12,13), 
     DT.datetime(2015,12,19), 
     DT.datetime(2016,1,24), 
     DT.datetime(2016,1,31), 
     DT.datetime(2016,2,17), 
     DT.datetime(2016,3,28), 
     DT.datetime(2016,3,31), 
     DT.datetime(2016,4,3),    
     DT.datetime(2016,4,16),    
    ]}) 

私はしたいと思いますデータフレームに新しい列を追加して、その顧客の過去90日間の時間加重平均の結果を表示します。

期待される結果(列Value_Result):

 Cus_ID Date Value Value_Result 
0 T313 2015-10-18 3.00   NaN  (No 90days history) 
1 T348 2015-11-14 2.00   NaN  (No 90days history) 
2 T313 2015-11-18 3.00   3  (3*31)/31 
3 T348 2015-12-13 4.00   2  (2*29)/29 
4 T313 2015-12-19 5.00   3  (3*62+3*31)/(62+31) 
5 T348 2016-01-24 3.00  2.743  (4*42+2*71)/(42+71) 
6 T329 2016-01-31 7.25   NaN  (No 90days history) 
7 T329 2016-02-17 10.25   7.25  (7.25*17)/17 
8 T348 2016-03-28 4.50   3  (3*64)/64 
9 T313 2016-03-31 11.75   NaN  (No 90days history) 
10 T329 2016-04-03 6.25  8.516  (10.25*46+7.25*63)/(46+63) 
11 T348 2016-04-16 6.00  3.279  (4.5*19+3*83)/(19+83) 

私はgroupby('Cus_ID')を使用しようとした圧延が適用されますが、私は難しさだけ後方に90日間検討する関数を作成しています。

すべての入力が高く評価されています。

+0

[この質問](http://stackoverflow.com/q/15771472/5276797)に似ています。 1つの選択肢は、毎日再サンプリングすることです(これが受け入れられる回答です)。リサンプリングがオプションでない場合、別の回答が適用するアドホック機能を提供します。 – IanS

答えて

1

ローリング機能が加重平均を使用する方法であるかどうかは分かりませんが、他の人がその方法を知っているかもしれません これは最も最適化された方法ですが、あなたが望む結果を生み出すことができます。これを取って、必要に応じて構築することができます。

大変感謝しております。pbpython article私はそれを読むことをお勧めします。

私のアプローチは、グループ(Cus_IDでグループ化)に適用される関数を作成することです。この関数は、そのグループの行を繰り返し処理し、上で説明したように加重平均を行い、これをグループに適用してグループを返します。このコードスニペットは、明確化のために冗長ですが、必要に応じて、変数の作成をすべて削除することでトリミングすることができます。

適用する機能は、あなたが、あなたはこのライン

df_test.groupby(by=['Cus_ID']).apply(tw_avg, 'Value', 'Date') 

これがもたらすであろうと探しているデータフレームを返すことができ、この

def tw_avg(group, value_col, time_col, new_col_name="time_weighted_average", days_back='-90 days', fill_value=np.nan): 
""" 
Will calculate the weighted (by day) time average of the group passed. 
It will not operate on the day it is evaulating but the previous days_back. 
Should be used with the apply() function in Pandas with groupby function 


Args: 
    group (pandas.DataFrame): Will be passed by pandas 
    value_col (str): Name of column with value to be averaged by weight 
    time_col (str): Name of column of with times in them 
    new_col_name (str): Name of new column to place time weighted average into, default: time_weighted_average 
    days_back (str): Time delta description as described in panda time deltas documentation, default: -90 days 
    fill_value (any): The value to fill rows which do not have data in days_back period, default: np.nan 

Returns: 
    (pandas.DataFrame): The modified DataFrame with time weighted average added to columns, np.nan if no 
    time weight average exist 
""" 
for idx, row in group.iterrows(): 
    # Filter for only values that are days_back for averaging. 
    days_back_fil = (group[time_col] < row[time_col]) & (group[time_col] >= row[time_col] + pd.Timedelta(days_back)) 
    df = group[days_back_fil] 

    df['days-back'] = (row[time_col] - df[time_col])/np.timedelta64(1, 'D') # need to divide by np.timedelta day to get number back 
    df['weight'] = df[value_col] * df['days-back'] 

    try: 
     df['tw_avg'] = df['weight'].sum()/df['days-back'].sum() 
     time_avg = df['tw_avg'].iloc[0] # Get single value of the tw_avg 
     group.loc[idx, new_col_name] = time_avg 
    except ZeroDivisionError: 
     group.loc[idx, new_col_name] = fill_value  

return group 

のように見えます

Cus_ID Date  Value time_weighted_average 
0 T313 2015-10-18 3.0 NaN 
1 T348 2015-11-14 2.0 NaN 
2 T313 2015-11-18 3.0 3.0 
3 T348 2015-12-13 4.0 2.0 
4 T313 2015-12-19 5.0 3.0 
5 T348 2016-01-24 3.0 2.743362831858407 
6 T329 2016-01-31 7.25 NaN 
7 T329 2016-02-17 10.25 7.25 
8 T348 2016-03-28 4.5 3.0 
9 T313 2016-03-31 11.75 NaN 
10 T329 2016-04-03 6.25 8.51605504587156 
11 T348 2016-04-16 6.0 3.2794117647058822 

ますこの関数を使用して、を持つ他の値の列に加重平均を適用できるようになりました3232引数を使用するか、時間ウィンドウの長さをdays_back引数で変更します。時間デルタの記述方法については、pandas time deltasページを参照してください。

+0

こんにちはジョシュ、本当にありがとう!これは本当に私が必要なものです! – Thor