如何为Pandas DataFrame添加早于目标时间的最近时间差列
问题
我有两个带datetime列的Pandas DataFrame,需要给df新增一列,存储df中每个时间点与dflogs里早于该时间点的最近datetime的秒级时间差,所以不能用merge_asof(direction="nearest")。
示例数据
df["datetime"]:
2023-11-15T18:00:00 2023-11-20T19:00:00 2023-11-20T20:00:00 2023-11-20T21:00:00
dflogs["datetime"]:
2023-11-17T18:00:00 2023-11-20T20:00:00
预期输出
2023-11-15T18:00:00 None (无匹配的更早时间) 2023-11-20T19:00:00 262800 (对应2023-11-17T18:00:00) 2023-11-20T20:00:00 0 (对应2023-11-20T20:00:00) 2023-11-20T21:00:00 3600 (对应2023-11-20T20:00:00)
我的错误尝试
我写了下面的函数,但无法正确运行:
def check_time_diff(item): item["timediff"] = (item["datetime"] - dflogs['datetime']).min() / pd.Timedelta(seconds=1) return item df = df.apply(check_time_diff, axis=1)
解决方案
你之前的方法错在没过滤dflogs里早于当前时间的记录,直接取所有时间差的最小值会拿到未来时间的负差值,结果完全不对。
用pd.Series.searchsorted可以快速定位每个时间点在dflogs中的对应位置,高效找到最近的更早时间:
步骤1:确保时间列是datetime类型
df['datetime'] = pd.to_datetime(df['datetime']) dflogs['datetime'] = pd.to_datetime(dflogs['datetime'])
步骤2:对dflogs的时间列排序(searchsorted要求序列有序)
dflogs_sorted = dflogs.sort_values('datetime').reset_index(drop=True) logs_dts = dflogs_sorted['datetime']
步骤3:计算时间差
# 找到每个df时间点在logs_dts中的插入位置,减1得到最近的更早时间索引 positions = logs_dts.searchsorted(df['datetime'], side='right') - 1 # 匹配对应的log时间,无匹配的设为NaT matched_log_dts = logs_dts.iloc[positions].reset_index(drop=True) matched_log_dts[positions < 0] = pd.NaT # 计算秒级时间差,无匹配的设为None df['timediff'] = (df['datetime'] - matched_log_dts).dt.total_seconds() df['timediff'] = df['timediff'].where(df['timediff'] >= 0, None)
最终结果
运行后df的timediff列完全符合预期:
| datetime | timediff |
|---|---|
| 2023-11-15 18:00:00 | None |
| 2023-11-20 19:00:00 | 262800.0 |
| 2023-11-20 20:00:00 | 0.0 |
| 2023-11-20 21:00:00 | 3600.0 |
效率说明
searchsorted基于二分查找,时间复杂度是O(n log m)(n是df行数,m是dflogs行数),比逐行遍历的apply(O(n*m))快得多,数据量大的时候差距尤其明显。
内容的提问来源于stack exchange,提问作者Scripter
相关产品推荐
相关产品推荐

