2017-02-25 2 views
3

다른 데이터 프레임의 날짜를 비교하여 데이터 프레임의 열 합계를 찾는 방법에 대해 잠시 질문을 받았습니다 (here). 그러나 이제는 비슷한 것을하고 싶지만 다른 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 번째 행에서 0을 얻으려면 끝에 병합을 사용하는 것이 현명하다고 생각합니다. – piRSquared

관련 문제