熊猫与逻辑合并

时间:2014-08-04 18:55:56

标签: python pandas

我想合并两个数据帧,但无法在没有迭代的情况下精确地弄清楚如何这样做。基本上,如果df1.date> = df2.start_date和df1.date< = df2.end_date,我想合并df2到df1的行。见下面的例子:

df1:
index   date         value
0       2012-08-01   82
1       2012-08-02   20
2       2012-08-03   94
...
n-1     2012-10-29   58
n       2012-10-30   73

df2:
index   start_date   end_date     other_value
0       2012-08-01   2012-09-04   'foo'
1       2012-09-05   2012-10-15   'bar'
2       2012-10-16   2012-11-01   'foobar'
...


final_df:
index   df2_index   date         value  other_value
0       0           2012-08-01   82     'foo'
1       0           2012-08-02   20     'foo'
2       0           2012-08-03   94     'foo'
...
n-1     2           2012-10-29   58     'foobar'
n       2           2012-10-30   73     'foobar'

我考虑过创建一个日期系列矢量来与df2合并,这样我就可以在日期结合,但它看起来非常手动,并没有利用熊猫的力量/速度。我还考虑过将df2扩展到单日,但如果没有手动/迭代类型的解决方案,就无法找到任何方法。

1 个答案:

答案 0 :(得分:5)

天真的迭代方法是O(n*m),其中n = len(df1)m = len(df2),因为对于df1中的每个日期,您必须检查其中包含m间隔。

如果df2定义的区间是不相交的,那么理论上有更好的方法:使用searchsorted查找df1中每个日期在start_dates中的位置,然后使用{ {1}}第二次找到每个日期在end_dates中的位置。当来自两次searchsorted的调用的索引相等时,日期就在一个区间内。

Searchsorted假设截止日期已排序并使用二进制搜索,因此每次调用都具有复杂度O(n * log(m))。

如果searchsorted足够大,使用m应该更快 而不是天真的迭代方法。

如果searchsorted不大,迭代方法可能会更快。


以下是使用m

的示例
searchsorted

import numpy as np import pandas as pd Timestamp = pd.Timestamp df1 = pd.DataFrame({'date': (Timestamp('2012-08-01'), Timestamp('2012-08-02'), Timestamp('2012-08-03'), Timestamp('2012-10-29'), Timestamp('2012-10-30'), Timestamp('2012-11-01'), Timestamp('2012-10-15'), # on then end_date Timestamp('2012-09-04'), # outside an interval Timestamp('2012-09-05'), # on then start_date ), 'value': (82, 20, 94, 58, 73, 1, 2, 3, 4)}) print(df1) df2 = pd.DataFrame({'end_date': ( Timestamp('2012-10-15'), Timestamp('2012-09-04'), Timestamp('2012-11-01')), 'other_value': ("foo", "bar", "foobar"), 'start_date': ( Timestamp('2012-09-05'), Timestamp('2012-08-01'), Timestamp('2012-10-16'))}) df2 = df2.reindex(columns=['start_date', 'end_date', 'other_value']) df2.sort(['start_date'], inplace=True) print(df2) # Convert to DatetimeIndexes so we can call the searchsorted method date_idx = pd.DatetimeIndex(df1['date']) start_date_idx = pd.DatetimeIndex(df2['start_date']) # Add one to the end_date so the original end_date will be included in the # half-open interval. end_date_idx = pd.DatetimeIndex(df2['end_date'])+pd.DateOffset(days=1) start_idx = start_date_idx.searchsorted(date_idx, side='right')-1 end_idx = end_date_idx.searchsorted(date_idx, side='right') df1['idx'] = np.where(start_idx == end_idx, end_idx, np.nan) result = pd.merge(df1, df2, left_on=['idx'], right_index=True) result = result.reindex(columns=['idx', 'date', 'value', 'other_value']) print(result) 等于

df1

date value 0 2012-08-01 82 1 2012-08-02 20 2 2012-08-03 94 3 2012-10-29 58 4 2012-10-30 73 5 2012-11-01 1 6 2012-10-15 2 7 2012-09-04 3 8 2012-09-05 4 等于

df2

以上代码产生

  start_date   end_date other_value
1 2012-08-01 2012-09-04         bar
0 2012-09-05 2012-10-15         foo
2 2012-10-16 2012-11-01      foobar