在不完全匹配的时间戳上合并两个熊猫数据框

Posted

技术标签:

【中文标题】在不完全匹配的时间戳上合并两个熊猫数据框【英文标题】:Merge two pandas dataframes on not exactly matching timestamps 【发布时间】:2015-11-07 23:58:54 【问题描述】:

我尝试在网站上搜索实现此功能的好方法(也尝试了一些关于分箱和时间序列的想法),但仍然找不到合适的灵魂。

问题来了

我有两个数据框:

    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 对应数据帧 2 中的索引 1、2、3

我需要将这些数据框合并到一个“时间”列中,以便数据框 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 微秒)。有没有一种很好的方法来合并它以按时间合并这些不完全匹配的时间,但可能给定一些匹配阈值?此外,每条记录不应超过一个匹配项。

如果清楚请告诉我。

非常感谢您!

【问题讨论】:

假设您的时间是一个字符串,您可以简单地做的一件事就是去掉时间的最后两位或三位数字,然后执行连接。例如x['time']=x['time'][:-3] 这是我的第一个想法,但这会产生一些重复的连接。我需要一种方法来唯一地连接这些记录,这意味着为每条记录找到一个最接近的匹配时间(最小绝对差)。 【参考方案1】:

不幸的是,这些“近距离匹配”在 pandas 中很少有超级简单的解决方案,但这还不错。您可以做的是从@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

【讨论】:

感谢您的回复,这是个好主意,我可以试试这个方法来解决这个问题【参考方案2】:

我最终做的是将我的数据帧分成相等的 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。

【讨论】:

以上是关于在不完全匹配的时间戳上合并两个熊猫数据框的主要内容,如果未能解决你的问题,请参考以下文章

我正在使用熊猫数据框,我需要在不使用循环的情况下将一整列纪元时间戳转换为人类时间

熊猫合并:合并同一列上的两个数据框,但保留不同的列

熊猫合并具有不同时间戳的数据帧一

加入两个熊猫数据框

如何匹配和合并两个具有完全不同值的数据框,数据框列中的数字除外?

Pandas DataFrame concat vs append