2017-02-20 80 views
2

我正在處理兩個數據集,每個數據集都有不同的日期。我想合併它們,但由於日期不完全匹配,我相信merge_asof()是最好的方法。熊貓:merge_asof()總計多行/不重複

然而,兩件事情發生了merge_asof()是不理想:

  1. 編號重複。
  2. 數字丟失。

下面的代碼是一個例子:

df_a = pd.DataFrame({'date':pd.to_datetime(['1/15/2016','3/15/2016','5/15/2016','7/15/2016'])}) 
df_b = pd.DataFrame({'date':pd.to_datetime(['1/1/2016','4/1/2016','5/1/2016','6/1/2016','7/1/2016']), 'num':[1,10,100,1000,10000]}) 

df_x = pd.merge_asof(df_a, df_b, on = 'date') 

這產生了:

 date num 
0 2016-01-15  1 
1 2016-03-15  1 
2 2016-05-15 100 
3 2016-07-15 10000 

,而是我會想:

 date num 
0 2016-01-15  1 
1 2016-03-15  0 
2 2016-05-15 110 
3 2016-07-15 11000 

...其中多套的落在日期之間的行將被累加起來,而不僅僅是最接近的行選擇。

這可能與merge_asof()或我應該尋找另一種解決方案?

回答

1

感謝張貼這個問題。它促使我花了幾個小時學習merge_asof來源。我不認爲你的解決方案可以大大改善,但我會提供一些調整,以加快它的幾個百分點。

# if we concat the original date vector, we will only need to merge once 
df_ax = pd.concat([df_a, df_a.rename(columns={'date':'date1'})], axis=1) 

# do the outer merge 
df_m = pd.merge(df_ax, df_b, on='date', how='outer').sort_values(by='date') 

# do a single rename, inplace 
df_m.rename(columns={'date': 'datex', 'date1': 'date'}, inplace=True) 

# fill the gaps to allow the groupby and sum 
df_m['num'].fillna(0, inplace=True) 
df_m['date'].fillna(method='bfill', inplace=True) 

# roll up the results. 
x = df_m.groupby('date').num.sum().reset_index() 
+0

嗨斯蒂芬,感謝您的改進。基本上我花了整整一天的時間來解決這個問題,但我仍然不滿意。我向上提出了你的答案,但我還沒有將它標記爲「答案」 - 我想看看其他人是否有更簡潔的方法來解決這個問題。 – pshep123

1

好的,回答了我自己的問題,但它似乎有點駭人聽聞,我會有興趣聽到其他答案。此外,這是而不是依靠merge_asof()

使用相同的DataFrames如上:

df_m = pd.merge(df_a, df_b, on = 'date', how = 'outer').sort_values(by = 'date') 

df_a = df_a.rename(columns = {'date':'date1'}) 

df_m = pd.merge(df_m, df_a, left_on = 'date', right_on = 'date1', how = 'outer') 

df_m['num'].fillna(0, inplace = True) 
df_m['date1'].fillna(method = 'bfill', inplace = True) 

x = df_m.groupby('date1').num.sum().reset_index().rename(columns = {'date1':'date'}) 
2

你在要求的B是A的過去和當前行之間我可以用這個很容易地獲得第一和最後一個索引行:

# get the previous dates from A: 
prev_dates = np.roll(df_a.date, 1) 
prev_dates[0] = pd.to_datetime(0) 

# get the first and last index of B: 
start = np.searchsorted(df_b.date, prev_dates) 
stop = np.searchsorted(df_b.date, df_a.date, side='right') - 1 

,現在我可以使用一些列表理解來得到我的結果:

>>> [df_b.num.values[begin:end+1].sum() for begin, end in zip(start, stop)] 
[1, 0, 110, 11000] 
+1

非常好!一個註釋:我不認爲你需要'list comprehension'中的'if/else'子句,因爲零長度列表將總和爲'0' –