使用 pandas/numpy 按时矢量化左连接
Vectorize left join on time with pandas/numpy
我有两个数据框:x
和 y
。我的 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'))
我有两个数据框:x
和 y
。我的 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'))