如何基于日期范围列表快速拆分带Datetime索引的Pandas Series
高效获取Pandas时间序列在指定日期范围内的数值集合
当然有更高效的实现方式啦!用iterrows()逐行遍历虽然直观,但数据量大的时候效率真的拉胯,我们可以借助Pandas的向量化特性和时间序列工具来优化,这里给你两种靠谱的方案:
方法一:利用IntervalIndex实现区间匹配
先把DataFrame里的时间范围转换成IntervalIndex,然后批量判断Series的索引属于哪个区间,最后聚合结果:
import pandas as pd # 构造示例数据 series = pd.Series( [1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17], index=pd.to_datetime([ "2020-06-09 10:20:00", "2020-06-09 10:25:00", "2020-06-09 10:30:00", "2020-06-09 10:35:00", "2020-06-09 10:40:00", "2020-06-09 10:45:00", "2020-06-09 10:50:00", "2020-06-09 10:55:00", "2020-06-09 11:00:00", "2020-06-09 11:05:00", "2020-06-09 11:10:00", "2020-06-09 11:15:00", "2020-06-09 11:20:00", "2020-06-09 11:25:00", "2020-06-09 11:30:00", "2020-06-09 11:35:00", "2020-06-09 11:40:00" ]) ) df = pd.DataFrame({ "start": pd.to_datetime(["2020-06-09 10:21:00", "2020-06-09 10:42:00"]), "end": pd.to_datetime(["2020-06-09 10:53:00", "2020-06-09 10:58:00"]) }) # 创建左开右开的IntervalIndex,匹配你的条件:索引>start且<end intervals = pd.IntervalIndex.from_arrays(df['start'], df['end'], closed='neither') # 批量筛选每个区间对应的Series数值 result = intervals.apply(lambda iv: series[series.index.isin(iv)].tolist()) print(result.tolist()) # 输出 [[2,3,4,5,6,7], [6,7,8]]
这种方法用Pandas原生的区间索引做匹配,代码简洁易读,同时避免了逐行循环的开销,比iterrows()高效不少。
方法二:用Numpy广播实现极致性能
如果你的数据量特别大,追求最快的执行速度,可以直接用Numpy的广播特性来批量完成所有区间的判断:
import numpy as np # 将时间序列和区间的时间转换成Numpy数组 series_idx = series.index.to_numpy() starts = df['start'].to_numpy() ends = df['end'].to_numpy() # 广播生成布尔掩码:每个Series索引是否在每个区间内 mask = (series_idx[:, None] > starts) & (series_idx[:, None] < ends) # 按列提取符合条件的数值 result = [series[mask[:, i]].tolist() for i in range(mask.shape[1])] print(result) # 输出 [[2,3,4,5,6,7], [6,7,8]]
这个方案完全基于底层的Numpy数组操作,避开了Pandas的一些额外开销,是性能最优的选择之一。
为什么这两种方法比iterrows()高效?
iterrows()本质是Python层面的逐行循环,每次循环都要单独处理一次布尔索引,不仅时间复杂度高,还会因为Python循环的开销拖慢速度。而上面的两种方法都是向量化操作,利用了Pandas/Numpy的C语言底层实现,同样的计算逻辑,执行速度能快几个数量级,数据量越大,优势越明显。
内容的提问来源于stack exchange,提问作者miepsik
相关产品推荐
相关产品推荐

