【问题标题】:How to join two dataframes when only some dates in one dataframe is present between two other dates in other dataframe?当一个数据框中只有一些日期存在于其他数据框中的其他两个日期之间时,如何连接两个数据框?
【发布时间】:2022-01-22 22:07:48
【问题描述】:

我有两个数据框:

df_A = pd.DataFrame({'start_date':['2021-04-01 00:00:00','2021-05-01 00:00:00', '2021-05-02 00:00:00'],'end_date':['2021-04-01 00:11:00','2021-05-01 00:06:00', '2021-05-03 00:00:00'], 'eventname':['birthday', 'wedding', 'birthday'] })
df_B = pd.DataFrame({'event_date':['2021-04-01 00:06:00','2021-05-01 00:03:00', '2021-05-04 00:00:00'],'price':[100,200,500]})
df_A['end_date'] = pd.to_datetime(df_A.end_date)
df_A['start_date'] = pd.to_datetime(df_A.start_date)
df_B['event_date'] = pd.to_datetime(df_B.event_date)

df_A

    start_date  end_date    eventname
0   2021-04-01  2021-04-01 00:11:00 birthday
1   2021-05-01  2021-05-01 00:06:00 wedding
2   2021-05-02  2021-05-03 00:00:00 birthday

df_B

event_date  price
0   2021-04-01 00:06:00 100
1   2021-05-01 00:03:00 200
2   2021-05-04 00:00:00 500

我想加入它们,使 event_date 列位于 df_A 的 start_dateend_date 列之间。这是我的代码:

df_A.index = pd.IntervalIndex.from_arrays(df_A['start_date'],df_A['end_date'],closed='both')
df_B['start_date'] = df_B['event_date'].apply(lambda x : df_A.iloc[df_A.index.get_loc(x)]['start_date'])
df_B

但是,由于 df_B 的 event_date 列上的某些值不在 df_A 中的任何 start_dateend_date 列之间,我得到了一个键错误。

这是我的预期输出:

event_date  price   start_date
0   2021-04-01 00:06:00 100 2021-04-01
1   2021-05-01 00:03:00 200 2021-05-01
2   2021-05-04 00:00:00 500 NaN

我尝试使用交集,但只有当值完全相等时才有效。我该怎么做?

【问题讨论】:

  • 如果两个数据帧不是太大,你可以merge给它们分配key=1,然后在合并的数据帧上应用逻辑。
  • 你为什么要标记 SQL ?如果您使用 SQL,请同时标记您的数据库系统

标签: python pandas datetime


【解决方案1】:

如果您可以避免非等连接,那么就这样做;使用分桶技术,类似于@Corralien 的优秀答案,其中箱不重叠(更快/更有效)。如果可能的话,另一种选择是找到一种引入合并连接的方法,并且可能合并您的最终输出 -> 步骤可能会更长,但是,我觉得如果做得正确,它会比非等连接更有效。但是,如果您只关心第一场比赛,那么pd.merge_asof 就足够了。

回到问题:

一种选择是通过conditional_join 来自pyjanitor

# pip install pyjanitor
import pandas as pd
import janitor

(df_A.conditional_join(
       df_B,  
       # column from left frame, column from right frame, comparision operator
       ('start_date', 'event_date', '<='), 
       ('end_date', 'event_date', '>='), 
       how = 'right')
   .filter(['event_date', 'price', 'start_date'])
)

           event_date  price start_date
0 2021-04-01 00:06:00    100 2021-04-01
1 2021-05-01 00:03:00    200 2021-05-01
2 2021-05-04 00:00:00    500        NaT

它的作用是将df_A 中的列与df_B 进行比较:

('start_date', 'event_date', '&lt;=') 表示检查来自df_Astart_date 是否是来自df_B&lt;= event_date。相同的概念适用于其他条件。这里的参数是变量args,意思是可以传递尽可能多的条件。列的类型必须相同(浮点数与浮点数、整数与整数、日期与日期……)。

在底层,它使用二进制搜索来寻找非 equi 连接(主要是为了避免笛卡尔连接,随着数据帧大小的增长,这可能会降低内存效率);对于这种情况下的范围连接,它使用简单的搜索来减少搜索空间以获取匹配的行。

该函数可以处理重叠索引,以及范围连接涉及两个不同列的场景 -> a &lt; b and c &gt; d

您可以查看更多示例here

【讨论】:

  • 你能解释一下这个概念吗?
  • 我尝试这个时得到一个空数据帧,它是否也适用于毫秒的时间戳?
  • 它适用于提供的示例数据。您介意分享更多包含秒数的数据吗?
  • @user42 当您可以以毫秒为单位分享示例数据帧以及预期输出时,我可以测试并查看失败的位置/原因。谢谢
【解决方案2】:

如果您的 start_dateend_date 不重叠,请创建一个区间索引并合并您的两个数据框:

bins = pd.IntervalIndex.from_arrays(df_A['start_date'], 
                                    df_A['end_date'],
                                    closed='both')

out = df_B.assign(interval=pd.cut(df_B['event_date'], bins)) \
          .merge(df_A.assign(interval=bins), on='interval', how='left')

print(out[['event_date', 'price', 'start_date']])

# Output:
           event_date  price start_date
0 2021-04-01 00:06:00    100 2021-04-01
1 2021-05-01 00:03:00    200 2021-05-01
2 2021-05-04 00:00:00    500        NaT

【讨论】:

  • 谢谢,这很好用,但在某些情况下,即使我的数据格式相同,我也会得到TypeError: Cannot convert Float64Index to dtype datetime64[ns]; integer values are required for conversion。你知道这是为什么吗?否则我会打开一个新问题`
  • 我明白为什么会出现错误,当我尝试加入在任何 start_date 和 end_date 间隔之间没有 event_date 的数据帧时,它失败了......有没有办法也要考虑这个吗?
  • 这很奇怪,因为您的数据框的最后一行(2021-05-04 00:00:00)没有落入一个区间。
  • 啊,我的意思是如果 interval 的所有值都导致 NaN,那么它会因上述错误而失败,我使用了一个简单的修复方法,我检查了 interval 是否导致空系列,然后我跳过了该数据帧的合并
  • 好的,我明白了。我虽然你会得到一个空的数据框而不是例外。 (如果我的回答适合您的需要,请考虑接受。谢谢:))
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-10-18
  • 1970-01-01
  • 2023-02-07
  • 2022-11-23
相关资源
最近更新 更多