使用 pandas/numpy 按时矢量化左连接

Vectorize left join on time with pandas/numpy

我有两个数据框:xy。我的 objective 是在 x 上左连接 y,其中 x.timestamp 在 y 最小值和最大值之间(并计算这些出现次数)。

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 行的 table 连接到 ~70k 行的 table 需要 45 到 60 秒) .

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

numpy 中是否有一种方法可以向量化此连接,或者是否有其他建议可以使此连接 运行 更快(不到 5 秒)?

对于也有重叠的一般解决方案,首先使用交叉连接,然后按条件过滤行,最后使用 Series.map an count matched values by 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)

x 中的时间戳与 y 中的 min/max 中的时间戳没有重叠。我不得不更改 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'))