Pandas merge_asof() 给出重复的匹配

Ste*_*ios 2 merge pandas

我有两个带有日期时间的数据框要合并。因为数据帧上的某些时间戳可能不完全相同,所以我认为最好使用 pandasmerge_asof()函数。

我想在“最近”值上加入时间戳,但要在给定的容差范围内(例如 +/- 5 分钟)。但是,该merge_asof()函数似乎将时间戳与容差内的第一个数据帧的所有时间戳相匹配。下面的例子可以更好地解释这一点。

import pandas as pd

df1 = pd.date_range("2019-01-01 00:00:00", "2019-01-01 00:04:00", freq='20s')
df1 = pd.DataFrame(df1, columns=['time'])

df2 = pd.DataFrame(["2019-01-01 00:02:00"], columns=['time'])
df2['time'] = pd.to_datetime(df2['time'])
df2['df2_col'] = 'df2'

merged_df = pd.merge_asof(df1, df2, left_on='time', right_on='time',
              tolerance=pd.Timedelta('40s'),
              allow_exact_matches=True,
              direction='nearest')

print (merged_df)
Run Code Online (Sandbox Code Playgroud)

实际输出:

                  time df2_col
0  2019-01-01 00:00:00     NaN
1  2019-01-01 00:00:20     NaN
2  2019-01-01 00:00:40     NaN
3  2019-01-01 00:01:00     NaN
4  2019-01-01 00:01:20     df2
5  2019-01-01 00:01:40     df2
6  2019-01-01 00:02:00     df2
7  2019-01-01 00:02:20     df2
8  2019-01-01 00:02:40     df2
9  2019-01-01 00:03:00     NaN
10 2019-01-01 00:03:20     NaN
11 2019-01-01 00:03:40     NaN
12 2019-01-01 00:04:00     NaN
Run Code Online (Sandbox Code Playgroud)

预期输出:

                  time df2_col
0  2019-01-01 00:00:00     NaN
1  2019-01-01 00:00:20     NaN
2  2019-01-01 00:00:40     NaN
3  2019-01-01 00:01:00     NaN
4  2019-01-01 00:01:20     NaN
5  2019-01-01 00:01:40     NaN
6  2019-01-01 00:02:00     df2
7  2019-01-01 00:02:20     NaN
8  2019-01-01 00:02:40     NaN
9  2019-01-01 00:03:00     NaN
10 2019-01-01 00:03:20     NaN
11 2019-01-01 00:03:40     NaN
12 2019-01-01 00:04:00     NaN
Run Code Online (Sandbox Code Playgroud)

这是预期的行为吗?我怎样才能获得预期的结果?

Ste*_*tef 5

实际输出是预期的行为:在最近的行中merge_asof(left, right)查找每一行(在容差范围内)。你想要的是稍有不同:你想找到的一排中的最接近。恐怕熊猫没有内置函数。 leftrightleftright

要实现您想要merge_asof(right, left)的结果,您可以进行反向操作,然后将结果与left. 为了在反向merge_asof结果中识别您需要的行,我们首先重置索引并使用此信息进行第二次合并:

x = pd.merge_asof(df2, df1.reset_index(), left_on='time', right_on='time',
              tolerance=pd.Timedelta('40s'),
              allow_exact_matches=True,
              direction='nearest')

merged_df = df1.merge(x[['df2_col','index']], how='left', left_index=True, right_on='index').set_index('index')
Run Code Online (Sandbox Code Playgroud)

结果:

                     time df2_col
index                            
0     2019-01-01 00:00:00     NaN
1     2019-01-01 00:00:20     NaN
2     2019-01-01 00:00:40     NaN
3     2019-01-01 00:01:00     NaN
4     2019-01-01 00:01:20     NaN
5     2019-01-01 00:01:40     NaN
6     2019-01-01 00:02:00     df2
7     2019-01-01 00:02:20     NaN
8     2019-01-01 00:02:40     NaN
9     2019-01-01 00:03:00     NaN
10    2019-01-01 00:03:20     NaN
11    2019-01-01 00:03:40     NaN
12    2019-01-01 00:04:00     NaN
Run Code Online (Sandbox Code Playgroud)

警告:在我们的示例中,df1 有一个未命名的索引。重置这个索引会将它变成一个默认名称为“index”的列,我们在第二次合并中使用它。但是,如果 df1 已经有一个名为“index”的列,那么新列的名称将是“index_0”,我们将不得不在第二次合并中使用这个名称而不是“index”。