You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何为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列完全符合预期:

datetimetimediff
2023-11-15 18:00:00None
2023-11-20 19:00:00262800.0
2023-11-20 20:00:000.0
2023-11-20 21:00:003600.0

效率说明

searchsorted基于二分查找,时间复杂度是O(n log m)(n是df行数,m是dflogs行数),比逐行遍历的apply(O(n*m))快得多,数据量大的时候差距尤其明显。


内容的提问来源于stack exchange,提问作者Scripter

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.03 01:09:50