将两个pandas数据帧合并到不完全匹配的时间戳上

时间:2015-08-14 16:45:37

标签: python pandas merge time-series dataframe

我尝试在网站上搜索一个很好的方法来实现这个(尝试了一些binning和时间序列的想法),但仍然找不到合适的灵魂。

这是问题

我有两个数据帧:

    index   name    time            price
1,  AAA,    11:37:09.359479,    58.480000,10
2,  ABC,    11:37:15.403268,    0.5000000,3
3,  ABB,    11:37:15.491515,    0.4500000,2
4,  AAA,    11:37:15.604864,    0.5000000,1
5,  ABC,    11:37:16.628756,    0.1800000,20
6,  ABD,    11:37:21.083105,    0.8000000,7
7,  AAA,    11:37:21.423480,    79.030000,10


index   name    time            price

1,  ABB,    11:37:15.491525,    0.4500000,2
2,  AAA,    11:37:15.604884,    0.5000000,1
3,  ABC,    11:37:16.628796,    0.1800000,20

正如您所看到的,数据帧1中的索引3,4,5具有来自dataftame 2的相应索引1,2,3

我需要将这些数据帧合并到一个'time'列中,以便对于来自数据帧1的记录3,4,5来自数据帧2的1,2,3在右边。

这应该是结果:

index_x name_x  time_x          price_x         name_y  time_y          price_y
1,  AAA,    11:37:09.359479,    58.480000,10    Nan ...
2,  ABC,    11:37:15.403268,    0.5000000,3     Nan ..  
3,  ABB,    11:37:15.491515,    0.4500000,2     ABB,    11:37:15.491525,    0.4500000,2
4,  AAA,    11:37:15.604864,    0.5000000,1     AAA,    11:37:15.604884,    0.5000000,1
5,  ABC,    11:37:16.628756,    0.1800000,20    ABC,    11:37:16.628796,    0.1800000,20
6,  ABD,    11:37:21.083105,    0.8000000,7     Nan ..
7,  AAA,    11:37:21.423480,    79.030000,10    Nan ..

我有麻烦,因为时间不完全一样(看最后2微秒)。有没有一种很好的方法来合并它的方式来按时合并这些不完全匹配,但给出一些匹配的阈值可能?每条记录也应该只有不超过一个匹配。

如果清楚,请告诉我。

非常感谢你!

2 个答案:

答案 0 :(得分:2)

不幸的是这些"关闭比赛"在熊猫中很少有一个超级简单的解决方案,但这并不是太糟糕。您可以做的是从@ CharlieHaley的解决方案开始,然后将其置于一个循环中,以便您可以进行最精确的匹配并丢弃不太精确的匹配。

当然,这仍然会让您决定使用哪些精度级别(在< decimal_range'中指定)。我开始在7的范围内保持输出简洁,但是你想要从1开始,然后决定你想要多高,因为更高的数字允许不那么精确的匹配。

(注意:我假设你的初始数据帧是' df1'和' df2'而且' time'是一个字符串,如果不是你需要先将其转换为字符串。)

decimal_range = range(7,9)

df1 = df1.reset_index()   # this creates column 'index' later used for
                          # dropping duplicates.  depending on your
                          # goals, may want to do for df2 instead of df1  
df3=pd.DataFrame()

for i in decimal_range:
    df1['time2'] = df1['time'].str[:-i]
    df2['time2'] = df2['time'].str[:-i]
    df3 = df3.append( df1.merge(df2,on=['name','time2'], how='inner'), )

df4 = df3.drop_duplicates(subset=['index','name'])

显示中间输出可能会更清楚。在i=7合并时,有3个匹配,但在i=8有4个匹配。 ' time2'列显示用于匹配的精度。

df3

   index name           time_x  price_x     time2           time_y  price_y
0      2  ABB  11:37:15.491515     0.45  11:37:15  11:37:15.491525     0.45
1      3  AAA  11:37:15.604864     0.50  11:37:15  11:37:15.604884     0.50
2      4  ABC  11:37:16.628756     0.18  11:37:16  11:37:16.628796     0.18
0      1  ABC  11:37:15.403268     0.50   11:37:1  11:37:16.628796     0.18
1      4  ABC  11:37:16.628756     0.18   11:37:1  11:37:16.628796     0.18
2      2  ABB  11:37:15.491515     0.45   11:37:1  11:37:15.491525     0.45
3      3  AAA  11:37:15.604864     0.50   11:37:1  11:37:15.604884     0.50

累积匹配后,只需删除重复项以保持更精确的匹配。

df4

   index name           time_x  price_x     time2           time_y  price_y
0      2  ABB  11:37:15.491515     0.45  11:37:15  11:37:15.491525     0.45
1      3  AAA  11:37:15.604864     0.50  11:37:15  11:37:15.604884     0.50
2      4  ABC  11:37:16.628756     0.18  11:37:16  11:37:16.628796     0.18
0      1  ABC  11:37:15.403268     0.50   11:37:1  11:37:16.628796     0.18

答案 1 :(得分:0)

我最终做的是将我的数据帧拆分为相等的bin,然后将它们合并到bin ID上。

这样做的一个缺点是,我只能这样做才能实现共同'共享'这两个数据帧中的时间间隔(对于第一个数据帧中的索引3,4,5)。

同一个bin中也可能有多条记录,在这种情况下我只是使用双方的最后一条记录进行合并。

所以我这样做(我的数据框名称是onTrade1和onTrade2):

commonFirstTime = max (onTrade1['exchangeTime'].min(), onTrade2['exchangeTime'].min())
commonLastTime = min (onTrade1['exchangeTime'].max(), onTrade2['exchangeTime'].max())


bins = numpy.linspace(commonFirstTime, commonLastTime, ((commonLastTime - commonFirstTime) / 1000))

groups1 = onTrade1.groupby(numpy.digitize(onTrade1['exchangeTime'], bins))
groups2 = onTrade2.groupby(numpy.digitize(onTrade2['exchangeTime'], bins))

然后我可以简单地将groups1与groups2合并到公共索引上。