我有2个大数据框df1
和df2
,它们都有一个列time
。我想加入这两张桌子。然而,可能并不总是完全匹配。在这种情况下,我想加入这样,我以一种有效的方式获取df1
的时间值之前发生的df2
的最新时间值。
例如,给定表
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
最终表应该是
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
with sorting:
%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]
})