如何用Pandas计算两个DataFrame间的最小正时间差
需求说明
有两个包含时间列的DataFrame:
- df1包含
Stop Time(结束时间)和Site(站点)列 - df2包含
Start Time(开始时间)和Site(站点)列
需要为df2中的每一条记录,计算其Start Time与df1所有Stop Time的正差值(即Start Time > Stop Time),筛选出其中的最小差值,并保留对应的df1的Site信息,最终存入新的df_bestDataFrame。要求用高效的Pandas方法替代循环实现。
示例数据
df1
Stop Time Site 2023-10-17 20:10:00.310 P2 2023-10-17 21:20:00.440 P1 2023-10-17 23:30:00.200 P2 2023-10-18 00:00:00.190 P1 2023-10-18 01:00:00.130 P1 2023-10-18 02:00:00.500 P2 2023-10-18 03:00:00.480 P1 2023-10-18 04:00:00.020 P2 2023-10-18 05:00:00.000 P1 2023-10-18 06:00:00.580 P2
df2
Start Time Site 2023-10-17 16:00:00.190 SMR 2023-10-17 17:05:00.050 SMR 2023-10-17 19:10:00.550 SMR 2023-10-17 21:40:00.530 SMR 2023-10-17 22:21:00.180 SMR 2023-10-18 05:21:00.090 SMR 2023-10-18 09:15:00.360 SMR 2023-10-18 11:54:00.160 SMR
比如df2中2023-10-17 21:40:00.530这条记录,匹配到df1中最近的Stop Time是2023-10-17 21:20:00.440,差值约20分钟,对应df1的Site为P1。
高效解决方案
使用Pandas的merge_asof方法,该方法专门用于按时间序列匹配最近的记录,效率远高于循环遍历。
步骤1:转换时间格式并排序
merge_asof要求两个DataFrame都按时间列排序,因此先转换时间类型并排序:
import pandas as pd # 转换时间列为datetime类型 df1['Stop Time'] = pd.to_datetime(df1['Stop Time']) df2['Start Time'] = pd.to_datetime(df2['Start Time']) # 按时间列排序 df1_sorted = df1.sort_values('Stop Time').reset_index(drop=True) df2_sorted = df2.sort_values('Start Time').reset_index(drop=True)
步骤2:时间匹配
使用merge_asof匹配df2每条记录对应的df1中最大的、小于等于当前Start Time的Stop Time(即差值最小的正差值):
df_best = pd.merge_asof( df2_sorted, df1_sorted, left_on='Start Time', right_on='Stop Time', direction='backward' # 找小于等于左表时间的最近右表记录 )
步骤3:计算差值并整理结果
计算时间差,过滤无效匹配(若df2的Start Time早于df1所有Stop Time,会得到NaN),并重命名列让结果更清晰:
# 计算时间差值 df_best['Time Difference'] = df_best['Start Time'] - df_best['Stop Time'] # 过滤无有效匹配的行(可选,根据需求调整) df_best = df_best.dropna(subset=['Time Difference']).reset_index(drop=True) # 重命名列区分两个DataFrame的Site df_best = df_best.rename(columns={'Site_x': 'df2_Site', 'Site_y': 'df1_Site'})
结果说明
最终的df_best会包含df2的原始信息、匹配到的df1的Stop Time和Site,以及对应的最小正时间差。以示例中的2023-10-17 21:40:00.530记录为例,会得到:
Start Time df2_Site Stop Time df1_Site Time Difference 3 2023-10-17 21:40:00.530 SMR 2023-10-17 21:20:00.440 P1 0 days 00:20:00.090000
效率优势
merge_asof基于排序后的线性扫描实现,时间复杂度为O(n log n + m log m)(主要来自排序步骤),相比循环遍历的O(n*m),在数据量较大时性能提升非常明显。
内容的提问来源于stack exchange,提问作者earnric

