使用 pandas.merge_asof 进行完全外连接

Posted

技术标签:

【中文标题】使用 pandas.merge_asof 进行完全外连接【英文标题】:Do full-outer-join with pandas.merge_asof 【发布时间】:2021-02-19 17:02:26 【问题描述】:

您好,我需要将一些时间序列数据与最近的时间戳对齐,所以我认为 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)需要进行这种“最近”合并,该怎么办?

【问题讨论】:

【参考方案1】:
    很遗憾,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

【讨论】:

您好,谢谢!您认为合并两个以上数据框的好方法是什么?请查看更新后的问题。 @circle999 这需要不同的解决方案。您可以创建一个新问题并参考该问题吗?您可以复制和粘贴所有数据,并添加多个示例数据框(例如 3 个而不是 2 个)。通常不赞成像这样更新问题。【参考方案2】:

这似乎很简单,但没有直接的解决方案。有一个选项可以再次合并以引入丢失的行:

# 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 进行完全外连接的主要内容,如果未能解决你的问题,请参考以下文章

在 pandas.merge_asof 之后保留两个合并键

Pandas merge_asof 显示两个数据框的日期

如何使 pandas merge_asof 不仅包含所有事件

使用完全独立于项目的设置进行测试

使用训练阶段使用的完全相同的数据集进行交叉验证是不是很好?

使用 Rails 6 ActiveRecord 进行完全外连接