使用 pandas.merge_asof 进行全外连接
Do full-outer-join with pandas.merge_asof
您好,我需要将一些时间序列数据与最近的时间戳对齐,所以我认为 pandas.merge_asof
可能是一个不错的选择。但是,它没有像标准 merge
方法那样设置 how='outer'
的选项。
一个例子可以是:
df1:
Value1
Time
2020-07-17 14:25:03.535906075 108
2020-07-17 14:25:05.457247019 110
2020-07-17 14:25:07.467777014 126
df2:
Value2
Time
2020-07-17 14:25:03.535018921 222
2020-07-17 14:25:04.545104980 150
2020-07-17 14:25:07.476825953 60
然后,例如,这样做 merge_asof
:
pd.merge_asof(df1, df2, left_index=True, right_index=True, direction='nearest', tolerance=pd.Timedelta('0.3s'))
结果将是:
Value1 Value2
Time
2020-07-17 14:25:03.535906075 108 222.0
2020-07-17 14:25:05.457247019 110 NaN
2020-07-17 14:25:07.467777014 126 60.0
但我想要的是:
Value1 Value2
Time
2020-07-17 14:25:03.535906075 108 222.0
2020-07-17 14:25:04.545104980 NaN 150.0 <---- this is the difference
2020-07-17 14:25:05.457247019 110 NaN
2020-07-17 14:25:07.467777014 126 60.0
基本上就像一个完整的外部连接。
有什么建议吗?提前致谢。
编辑:
所以这是2个数据帧的情况。例如,如果有 10 个数据帧(即 df1, df2, ..., df10
)需要进行这种“最近”合并,那么什么是好的方法呢?
- 不幸的是,
pd.merge_asof
中没有 how
参数,就像 pd.merge
一样,否则您可以简单地传递 how='outer'
.
- 作为解决方法,您可以
append
手动从其他数据帧中获取不匹配的值
- 然后,用
.sort_index()
对索引进行排序
df3 = pd.merge_asof(df1, df2, left_index=True, right_index=True, direction='nearest', tolerance=pd.Timedelta('0.3s'))
df4 = pd.merge_asof(df2, df1, left_index=True, right_index=True, direction='nearest', tolerance=pd.Timedelta('0.3s'))
df5 = df3.append(df4[df4['Value1'].isnull()]).sort_index()
df5
Out[1]:
Value1 Value2
Time
2020-07-17 14:25:03.535906075 108.0 222.0
2020-07-17 14:25:04.545104980 NaN 150.0
2020-07-17 14:25:05.457247019 110.0 NaN
2020-07-17 14:25:07.467777014 126.0 60.0
这看起来很简单,但没有直接的解决方案。有一个选项可以再次合并以引入缺失的行:
# enumerate the rows of `df2` to later identify which are missing
df2 = df2.reset_index().assign(idx=np.arange(df2.shape[0]))
(pd.merge_asof(df1.reset_index(),
df2[['Time','idx']],
on='Time',
direction='nearest',
tolerance=pd.Timedelta('0.3s'))
.merge(df2, on='idx', how='outer') # merge back on row number
.assign(Time=lambda x: x['Time_x'].fillna(x['Time_y'])) # fill the time
.set_index(['Time']) # set index back
.drop(['Time_x','Time_y','idx'], axis=1)
.sort_index()
)
Value1 Value2
Time
2020-07-17 14:25:03.535906075 108.0 222.0
2020-07-17 14:25:04.545104980 NaN 150.0
2020-07-17 14:25:05.457247019 110.0 NaN
2020-07-17 14:25:07.467777014 126.0 60.0
您好,我需要将一些时间序列数据与最近的时间戳对齐,所以我认为 pandas.merge_asof
可能是一个不错的选择。但是,它没有像标准 merge
方法那样设置 how='outer'
的选项。
一个例子可以是:
df1:
Value1
Time
2020-07-17 14:25:03.535906075 108
2020-07-17 14:25:05.457247019 110
2020-07-17 14:25:07.467777014 126
df2:
Value2
Time
2020-07-17 14:25:03.535018921 222
2020-07-17 14:25:04.545104980 150
2020-07-17 14:25:07.476825953 60
然后,例如,这样做 merge_asof
:
pd.merge_asof(df1, df2, left_index=True, right_index=True, direction='nearest', tolerance=pd.Timedelta('0.3s'))
结果将是:
Value1 Value2
Time
2020-07-17 14:25:03.535906075 108 222.0
2020-07-17 14:25:05.457247019 110 NaN
2020-07-17 14:25:07.467777014 126 60.0
但我想要的是:
Value1 Value2
Time
2020-07-17 14:25:03.535906075 108 222.0
2020-07-17 14:25:04.545104980 NaN 150.0 <---- this is the difference
2020-07-17 14:25:05.457247019 110 NaN
2020-07-17 14:25:07.467777014 126 60.0
基本上就像一个完整的外部连接。
有什么建议吗?提前致谢。
编辑:
所以这是2个数据帧的情况。例如,如果有 10 个数据帧(即 df1, df2, ..., df10
)需要进行这种“最近”合并,那么什么是好的方法呢?
- 不幸的是,
pd.merge_asof
中没有how
参数,就像pd.merge
一样,否则您可以简单地传递how='outer'
. - 作为解决方法,您可以
append
手动从其他数据帧中获取不匹配的值 - 然后,用
.sort_index()
对索引进行排序
df3 = pd.merge_asof(df1, df2, left_index=True, right_index=True, direction='nearest', tolerance=pd.Timedelta('0.3s'))
df4 = pd.merge_asof(df2, df1, left_index=True, right_index=True, direction='nearest', tolerance=pd.Timedelta('0.3s'))
df5 = df3.append(df4[df4['Value1'].isnull()]).sort_index()
df5
Out[1]:
Value1 Value2
Time
2020-07-17 14:25:03.535906075 108.0 222.0
2020-07-17 14:25:04.545104980 NaN 150.0
2020-07-17 14:25:05.457247019 110.0 NaN
2020-07-17 14:25:07.467777014 126.0 60.0
这看起来很简单,但没有直接的解决方案。有一个选项可以再次合并以引入缺失的行:
# enumerate the rows of `df2` to later identify which are missing
df2 = df2.reset_index().assign(idx=np.arange(df2.shape[0]))
(pd.merge_asof(df1.reset_index(),
df2[['Time','idx']],
on='Time',
direction='nearest',
tolerance=pd.Timedelta('0.3s'))
.merge(df2, on='idx', how='outer') # merge back on row number
.assign(Time=lambda x: x['Time_x'].fillna(x['Time_y'])) # fill the time
.set_index(['Time']) # set index back
.drop(['Time_x','Time_y','idx'], axis=1)
.sort_index()
)
Value1 Value2
Time
2020-07-17 14:25:03.535906075 108.0 222.0
2020-07-17 14:25:04.545104980 NaN 150.0
2020-07-17 14:25:05.457247019 110.0 NaN
2020-07-17 14:25:07.467777014 126.0 60.0