pandas无apply高效判断多个时间戳是否落在每行START和END区间内
Pandas无apply实现判断时间区间是否包含指定时间点
原方案错误原因
原写法分开判断「存在时间戳≥当前行START」和「存在时间戳≤当前行END」,没有要求两个条件对应同一个时间戳,因此当出现比如["2019-01-01", "2021-01-01"]这类跨全区间的时间戳组合时,会输出全True的错误结果。
高性能实现方案
方案1:numpy广播向量化实现(逻辑直观,通用场景首选)
利用numpy广播机制直接生成二维布尔矩阵判断,全程无Python级循环,性能远高于apply:
import numpy as np import pandas as pd # 你的原始数据和timestamps定义部分 data = [["2020-01-01", "2020-01-01"], ["2020-01-02", "2020-01-04"], ["2020-01-05", "2020-01-06"]] df = pd.DataFrame(data, columns=["START", "END"]).astype({"END": "datetime64[ns]" , "START": "datetime64[ns]"}) timestamps = pd.Series(["2020-01-02", "2020-01-03"], dtype="datetime64[ns]") # 核心逻辑 # 构造 (df行数, timestamps长度) 的布尔矩阵,逐元素判断时间戳是否≥对应行START mask_ge_start = df["START"].values[:, np.newaxis] <= timestamps.values # 构造同维度布尔矩阵,逐元素判断时间戳是否≤对应行END mask_le_end = df["END"].values[:, np.newaxis] >= timestamps.values # 逐行检查是否至少有一个时间戳同时满足两个条件 df["has_match"] = (mask_ge_start & mask_le_end).any(axis=1)
输出的has_match列结果为[False, True, False],符合预期;如果用错误测试用的timestamps["2019-01-01", "2021-01-01"],输出结果为全False,完全正确。
方案2:IntervalIndex实现(适合timestamps数量远小于df行数的场景)
如果timestamps的长度远小于df的行数,可以用IntervalIndex进一步优化性能:
# 构造左闭右闭的区间索引 intervals = pd.IntervalIndex.from_arrays(df["START"], df["END"], closed="both") # 查找每个时间戳命中的区间位置 hit_indexes = intervals.get_indexer(timestamps) # 标记有命中的行 df["has_match"] = df.index.isin(hit_indexes[hit_indexes != -1])
该方案时间复杂度仅为O(n + m log n)(n为df行数,m为timestamps长度),在df行数很大、timestamps很少的场景下性能优势更明显。
内容的提问来源于stack exchange,提问作者mexx
相关产品推荐
相关产品推荐

