如何加速加入非相等时间值的大型数据集
how to speed up joining large datasets on nonequal time values
我有 2 个大型数据框 df1
和 df2
,它们都有一列 time
。我想加入这 2 tables。但是,可能并不总是完全匹配。在这种情况下,我想加入,以便我以有效的方式获取 df2
中发生在 df1
时间值之前的最新时间值。
例如,给定 tables
df1
Time | val_1
------------------------
1/1/1980 1:00:00 | 1
1/1/1980 2:00:00 | 2
1/1/1980 3:00:00 | 3
1/1/1980 4:00:00 | 4
df2
time | val_2
------------------------
1/1/1980 1:00:00 | 5
1/1/1980 1:59:59 | 6
1/1/1980 3:00:01 | 7
1/1/1980 3:30:30 | 8
最后的table应该是
time | val_1 | val_2
--------------------------------
1/1/1980 1:00:00 | 1 | 5
1/1/1980 2:00:00 | 2 | 6
1/1/1980 3:00:00 | 3 | 6
1/1/1980 4:00:00 | 4 | 8
我目前正在这样做,但运行时间太长
def prevrow(t):
return df2.iloc[df2['time'].apply(lambda x: t - x if t >= x else np.nan).idxmin()]
pd.concat([df1,df1['Time'].apply(prevrow)], axis=1)
我该如何加快速度?
我们可以尝试使用 merge_asof
代替:
# df1 = df1.rename(columns={'Time': 'time'})
new_df = pd.merge_asof(df1, df2, on='time', direction='backward')
*注意direction='backward'
是默认方向,所以不需要指定,但是,这是我们要查找的匹配方向。
new_df
:
time val_1 val_2
0 1980-01-01 01:00:00 1 5
1 1980-01-01 02:00:00 2 6
2 1980-01-01 03:00:00 3 6
3 1980-01-01 04:00:00 4 8
需要注意的是 time
列必须在两个 DataFrame 中排序,这可以通过 sort_values
完成(如果尚未完成)
# df1 = df1.rename(columns={'Time': 'time'})
new_df = pd.merge_asof(df1.sort_values('time'),
df2.sort_values('time'),
on='time')
一些时间信息来自 %timeit:
原始方法:
def prevrow(t):
return df2.iloc[df2['time'].apply(lambda x: t - x if t >= x else np.nan).idxmin()]
%timeit pd.concat([df1,df1['time'].apply(prevrow)], axis=1)
2.29 ms ± 172 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
merge_asof
不排序:
%timeit pd.merge_asof(df1, df2, on='time')
1.13 ms ± 50.9 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)
merge_asof
排序:
%timeit pd.merge_asof(df1.sort_values('time'), df2.sort_values('time'), on='time')
1.46 ms ± 27.6 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)
数据和导入:
import pandas as pd
df1 = pd.DataFrame({
'time': pd.to_datetime(['1/1/1980 1:00:00', '1/1/1980 2:00:00',
'1/1/1980 3:00:00', '1/1/1980 4:00:00']),
'val_1': [1, 2, 3, 4]
})
df2 = pd.DataFrame({
'time': pd.to_datetime(['1/1/1980 1:00:00', '1/1/1980 1:59:59',
'1/1/1980 3:00:01', '1/1/1980 3:30:30']),
'val_2': [5, 6, 7, 8]
})
我有 2 个大型数据框 df1
和 df2
,它们都有一列 time
。我想加入这 2 tables。但是,可能并不总是完全匹配。在这种情况下,我想加入,以便我以有效的方式获取 df2
中发生在 df1
时间值之前的最新时间值。
例如,给定 tables
df1
Time | val_1
------------------------
1/1/1980 1:00:00 | 1
1/1/1980 2:00:00 | 2
1/1/1980 3:00:00 | 3
1/1/1980 4:00:00 | 4
df2
time | val_2
------------------------
1/1/1980 1:00:00 | 5
1/1/1980 1:59:59 | 6
1/1/1980 3:00:01 | 7
1/1/1980 3:30:30 | 8
最后的table应该是
time | val_1 | val_2
--------------------------------
1/1/1980 1:00:00 | 1 | 5
1/1/1980 2:00:00 | 2 | 6
1/1/1980 3:00:00 | 3 | 6
1/1/1980 4:00:00 | 4 | 8
我目前正在这样做,但运行时间太长
def prevrow(t):
return df2.iloc[df2['time'].apply(lambda x: t - x if t >= x else np.nan).idxmin()]
pd.concat([df1,df1['Time'].apply(prevrow)], axis=1)
我该如何加快速度?
我们可以尝试使用 merge_asof
代替:
# df1 = df1.rename(columns={'Time': 'time'})
new_df = pd.merge_asof(df1, df2, on='time', direction='backward')
*注意direction='backward'
是默认方向,所以不需要指定,但是,这是我们要查找的匹配方向。
new_df
:
time val_1 val_2
0 1980-01-01 01:00:00 1 5
1 1980-01-01 02:00:00 2 6
2 1980-01-01 03:00:00 3 6
3 1980-01-01 04:00:00 4 8
需要注意的是 time
列必须在两个 DataFrame 中排序,这可以通过 sort_values
# df1 = df1.rename(columns={'Time': 'time'})
new_df = pd.merge_asof(df1.sort_values('time'),
df2.sort_values('time'),
on='time')
一些时间信息来自 %timeit:
原始方法:
def prevrow(t):
return df2.iloc[df2['time'].apply(lambda x: t - x if t >= x else np.nan).idxmin()]
%timeit pd.concat([df1,df1['time'].apply(prevrow)], axis=1)
2.29 ms ± 172 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
merge_asof
不排序:
%timeit pd.merge_asof(df1, df2, on='time')
1.13 ms ± 50.9 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)
merge_asof
排序:
%timeit pd.merge_asof(df1.sort_values('time'), df2.sort_values('time'), on='time')
1.46 ms ± 27.6 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)
数据和导入:
import pandas as pd
df1 = pd.DataFrame({
'time': pd.to_datetime(['1/1/1980 1:00:00', '1/1/1980 2:00:00',
'1/1/1980 3:00:00', '1/1/1980 4:00:00']),
'val_1': [1, 2, 3, 4]
})
df2 = pd.DataFrame({
'time': pd.to_datetime(['1/1/1980 1:00:00', '1/1/1980 1:59:59',
'1/1/1980 3:00:01', '1/1/1980 3:30:30']),
'val_2': [5, 6, 7, 8]
})