2017-02-25 8 views
3

別のデータフレームの日付を比較してデータフレーム内の列の合計を見つける方法について質問をしました。しかし、私は今、同様のことをしたいが、別のIDと正確に一致する日付を持つIDを含める。パンダ:日付範囲とIDに基づいてデータフレームに金額を追加

df_a = pd.DataFrame({ 
     'end':pd.to_datetime(['1/15/2016','1/15/2016','3/15/2016','5/15/2016','5/15/2016','7/15/2016']), 
     'ID':[1,2,1,2,1,1] 
    }) 

df_a['start'] = df_a.groupby('ID')['end'].shift().fillna(0) 
df_a = df_a[['start','end','ID']] 

df_b = pd.DataFrame({ 
     'date':pd.to_datetime(['1/1/2016','1/1/2016','2/1/2016','2/1/2016','3/1/2016','3/1/2016','6/1/2016','6/1/2016','7/1/2016','7/1/2016','8/1/2016']), 
     'ID':  [1, 2, 1, 2, 1, 2, 2, 1, 1,  2,  2], 
     'amount': [1, 2, 10, 20, 100, 200, 2000, 1000, 10000, 20000, 200000] 
    }) 

そして、私の所望の出力::私はmerge()merge_asof()combine_first()groupby()を試してみましたが、近い得ている

  start  end ID amount 
0 1970-01-01 2016-01-15 1  1 
1 1970-01-01 2016-01-15 2  2 
2 2016-01-15 2016-03-15 1  110 
3 2016-01-15 2016-05-15 2  220 
4 2016-03-15 2016-05-15 1  0 
5 2016-05-15 2016-07-15 1 11000 

、すべてではない方法

は、ここに私のコードです。ここで

は働く非パンダのバージョンですが、大規模なデータセットのために、私はこれが非常に遅くなることが想像:

amount = [] 
for s, e, i in zip(df_a['start'], df_a['end'], df_a['ID']): 
    amount.append(df_b['amount'][(s < df_b['date']) & (df_b['date'] <= e) & (df_b['ID'] == i)].sum()) 

df_a['amount'] = pd.Series(amount) 

は、事前に感謝をいくつかの助けを大好きです。

答えて

2

あなたの答えはかなり良いです。 fill_valuereindexを使用すると、なかなか良さそうですそれintdtype

mux = pd.MultiIndex.from_arrays(df_a.values.T, names=df_a.columns) 

kws = dict(
    left_on='date', right_on='start', 
    allow_exact_matches=True, by='ID') 
mrg = pd.merge_asof(df_b, df_a, **kws).query('date <= end') 
grp = mrg.groupby(['start', 'end', 'ID']).amount.sum() 
grp.reindex(mux, fill_value=0).reset_index() 

     start  end ID amount 
0 1970-01-01 2016-01-15 1  1 
1 1970-01-01 2016-01-15 2  2 
2 2016-01-15 2016-03-15 1  110 
3 2016-01-15 2016-05-15 2  220 
4 2016-03-15 2016-05-15 1  0 
5 2016-05-15 2016-07-15 1 11000 
+0

これは正しい答えとしてマークするつもりですが、うまくいくからですが、*うわーです。それは私が消化するのに時間が必要ないくつかのより高いレベルのパンダです。素晴らしい学習体験、ありがとう! – pshep123

2

私は元の質問(感謝@piRSquared)で共有したリンクに基づいて自分の質問に答えたと思いますが、ちょっとしたコードを追加する必要がありました。私はこれが最も効率的な方法ではないと推測しており、他の考えを得ることに興味があります。

# Merge DataFrames, find date ranges, and add amounts  
df_c = pd.merge_asof(df_b, df_a, left_on = 'date', right_on = 'start', by = 'ID') \ 
     .query('date <= end').groupby(['end','ID'])['amount'].sum().reset_index() 

# But that leaves out ranges for which there is no data 
# so need to merge back in the original dates and fill NaNs with 0  
df_c = df_a.merge(df_c, how = 'outer').fillna(0) 

     start  end ID amount 
0 1970-01-01 2016-01-15 1  1.0 
1 1970-01-01 2016-01-15 2  2.0 
2 2016-01-15 2016-03-15 1 110.0 
3 2016-01-15 2016-05-15 2 220.0 
4 2016-03-15 2016-05-15 1  0.0 
5 2016-05-15 2016-07-15 1 11000.0 
+0

を維持するので、私はこれが好きです。私は好みに応じて少し違ったやり方をしましたが、最後にマージを使って4行目のゼロを得ることは賢明だと思います。 – piRSquared

関連する問題