2017-02-20 81 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' –