2016-06-01 2 views
0

私は顧客のすべてのトランザクションデータを持つデータフレームを持っています。列はmailid、txn_date、cityです。今では、01jan2016からの顧客を考慮する必要がある状況があります。メールファイルごとに、txnデータをベースファイルからフェッチし、最後の12ヶ月のデータ(最終Txn日付と-365days timedeltaの間の日付)彼らの最大取引都市名を見つける。 データフレームをルーピングし、別のデータフレームから関連データをフェッチする:PANDAS

サンプルベースのデータフレーム

#df 
maild txn_date city 
satya 2015-07-21 a 
satya 2015-08-11 b 
satya 2016-05-11 c 
xyz  2016-06-01 f 
satya 2016-06-01 a 
satya 2016-06-01 b 

私は彼らの最後の12Monthトランザクションのそれぞれを取得する必要があるので、私はDの各MAILIDため

d = df[['mailid', 'txn-date']][df['txn_date'] >= '2016-01-01'] 

今やった2016年1月1日からカスト必要としてベースデータフレームdfからのデータを収集し、取引された最大都市を計算する。そのために私は

のようなforループを使用しています
x = d.groupby(['mailid'])['txn-date'].max().reset_index() #### finding their last transacted date to find out a 12 Month back date 
x['max_city'] = 'N' ## giving default value as 'N' 
for idx,row in x.iterrows(): 
g = row[1].date() 
h = g-timedelta(days=365) ###getting the last 12 Month date 
y = df[(df['mailid']==row[0]) & (df['txn_date'] >= str(h))] 
y.sort(['txn_date'],ascending=True,inplace=True) ### sorting it bcoz i want to consider the last txn when count for one or more cities become same 
c = y.groupby(['mailid','city']).size().reset_index() 
v = c.groupby(['mailid'])[0].max().reset_index() 
dca = pd.merge(y,c,on=['mailid','city'],how='left') 
dcb = pd.merge(dca,v,on=['mailid',0]) 
m = dcb.drop_duplicates(['mailid'],take_last=True) 
row[2] = m['city'].unique()[0] 

O/P:

maild max_city 
satya b ### as in last 12 month 2016-06-01 2015-06-01 txn in a=2 b= 2 so last is b so will consider b as max city 
xyz  f 

私のコードは動作しますけど(私は未整理であると確信していると私は練習していたとして何の適切な命名規則を使用しません)、データフレームx内に存在する各顧客のメインBase dataFrame dfをループします。

私の主な関心事は、私のdfが100Mlnの行になり、xが6mlnの行になるということです。 forループは6Mln回実行され、一致したmailidデータを取得するためにdfをヒットし、処理された最大都市を見つける操作を行います。

1分で3のmailidの最大都市を計算します。 6mlnのために2mln分かかるでしょう...これは深刻な問題になります...

シナリオを最適化する方法については、皆さんから提案が必要です。メインベースの回数を減らし、より便利なPANDASを適用します。私はまだそれができません)...

お願い、お勧め!!!ありがとうございます。

+0

都市はテキスト列で、*取引先都市名*を集計しますか?都市数の最大値を意味しますか?アルファベット順に最も高い都市ですか? – Parfait

+0

@ Parfait-まったく!私は都市数を最大にしたい、または好きな都市を言うことができます... – Satya

答えて

1

groupbyを使用して、機能をより効率的に適用できます。

cityとmaildの両方でグループ化し、トランザクションの最大日付と合計数を取得します。最大の日付で並べ替えます。

g=d.groupby(['maild','city'])['txn_date'].agg(['count','max']).sort_values('max',ascending=False) 

それからちょうどによってグループmaild、最高数の指数

g.groupby(level='maild')['count'].agg(lambda x:pd.Series.argmax(x)[1]) 

を得ること -

maild 
satya a 
xyz  f 

ところで、あなたの例では両方のAのサティヤのためのトランザクションを持っているし、 2016-01-01のb。 bが正しい答えであるとはどのように判断しましたか?ここで

1

が読み少し楽かもしれない代替です:

def f(g): 
    dc=g.groupby('city')['txn_date'] 
    dc_sorted=dc.agg(['count','max']).sort_values('max',ascending=False) 
    return dc_sorted['count'].argmax() 

d.groupby(['maild']).apply(f) 

しかし、私はapplyは非常に大きなテーブルにいくつかのパフォーマンスの問題を持っているだろうと思われます。

+0

@ Victor-あなたの提案はデータフレーム全体でうまくいきますが、私は別の条件を持っています---それぞれのメールIDには最後の12Monthsトランザクションを考慮する必要があります。あなたのコードにその条件を適合させる方法は?例。もしfo r 'satyaが別のtxnの日付'2014-02-01'があるとすれば、彼の最後のtxn日付は '2016-06-01'で、365日のデルタは'2015-06-01 '...だからこの状況も達成しなければならない。あなたは助けてもらえますか? – Satya

+0

12ヶ月以内のものすべてを除外するために、まずデータセット全体をフィルタリングできると思われますか? –

0

applytransformの機能を考えてみましょう。最初の実行グループは、maildcityで時間枠に応じてカウントし、秒はmaildでカウントを最大化します。最後にgroupby()のフィルタリングにより、カウントが最大カウントに等しいペアが保持されます。

def last12mos(row): 
    row['count'] = 0 
    row.loc[row['txn_date'] >= row['txn_date'].max() - timedelta(days=365), 'count'] = 1 
    row['count'] = row['count'].sum() 
    return(row) 

basedf = basedf.groupby(['maild', 'city']).apply(last12mos)  
basedf['maxcount'] = basedf.groupby(['maild'])['count'].transform(max) 

finaldf = basedf[basedf['count'] == basedf['maxcount']].\ 
              groupby(['maild', 'city']).aggregate(max) 
関連する問題