【问题标题】:Vectorize left join on time with pandas/numpy使用 pandas/numpy 准时矢量化左连接
【发布时间】:2021-05-20 01:55:45
【问题描述】:

我有两个数据框:xy。我的目标是在 x 上加入 y,其中 x.timestamp 介于 y min 和 max 之间(并计算这些出现次数)。

x.shape
(69593, 1)

x.head()
timestamp   count
4   2013-06-01 04:12:34 0
5   2013-06-01 04:19:08 0
6   2013-06-01 05:18:35 0
7   2013-06-01 06:00:19 0
8   2013-06-01 09:16:13 0

y.head()
min max
0   2013-06-02 09:10:51 2013-06-02 10:27:44
1   2013-06-12 03:08:35 2013-06-12 03:08:35
2   2013-08-03 09:11:35 2021-01-26 23:05:17

y.shape
(3, 2)

在这种情况下,对每一行使用 lambda 函数是可行的,但速度非常慢(将 3 行的表连接到约 70k 行的表需要 45 到 60 秒)。

%%time
x['count'] = \
    x.apply(lambda r: len(y.loc[(y['min']<=r['timestamp']) & (y['max']>=r['timestamp'])]), axis=1)

numpy 中是否有一种方法可以对该连接进行矢量化,或者是否有其他建议可以使该连接运行得更快(5 秒以下)?

【问题讨论】:

    标签: python pandas numpy join vectorization


    【解决方案1】:

    对于一般的解决方案,也可以先使用交叉连接,然后按条件过滤行,最后添加Series.map 的新列,计数匹配值Series.value_counts

    df = x.assign(a=1).merge(y.assign(a=1), on='a')
    s = df.loc[(df['min']<=df['timestamp']) & (df['max']>=df['timestamp']), 'timestamp']
    
    x['count'] = x['timestamp'].map(s.value_counts()).fillna(0).astype(int)
    

    【讨论】:

      【解决方案2】:

      x 中的时间戳与y 中的最小值/最大值之间没有重叠。我不得不更改y 数据框中的第一条记录:

      >>> y
      Out[124]: 
                        min                 max
      0 2013-05-10 09:10:51 2013-06-02 10:27:44
      1 2013-06-12 03:08:35 2013-06-12 03:08:35
      2 2013-08-03 09:11:35 2021-01-26 23:05:17
      

      但是当您确实有重叠时,您可以使用merge_asof() 进行合并:

      foo = pd.merge_asof(x, y, left_on='timestamp', right_on='min', direction='backward')
      valid_idx = np.where(foo.timestamp >= foo['max'])[0]
      new_cols = foo.loc[valid_idx, :]
      foo = pd.merge(x, new_cols, left_index=True, right_index=True, suffixes=('_1', '_2'))
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2021-04-06
        • 2018-03-17
        • 1970-01-01
        • 2017-11-07
        • 2023-03-20
        • 2021-04-27
        • 2020-04-06
        相关资源
        最近更新 更多