如何优化Pandas中时间区间转换次数计算的运行时长
高效实现同Base分组下时间区间内记录计数需求
需求说明
统计同一Base分组下,Time_of_Fetch处于当前行Time_of_Fetch至Time_Completed区间内的记录数量,并将该计数作为新列Check_value添加至DataFrame。
样本数据
Time_Completed Time_of_Fetch Base Number of event 03-06-2022 14:56 03-06-2022 14:14 Q112 12 03-06-2022 14:54 03-06-2022 14:14 Q112 11 03-06-2022 14:51 03-06-2022 14:18 Q112 9 03-06-2022 14:52 03-06-2022 14:21 Q112 8 03-06-2022 15:07 03-06-2022 14:25 Q112 8 03-06-2022 14:54 03-06-2022 14:25 Q112 7 03-06-2022 14:50 03-06-2022 14:25 Q112 5 03-06-2022 15:11 03-06-2022 14:27 Q112 5 03-06-2022 15:17 03-06-2022 14:29 Q112 4 03-06-2022 15:19 03-06-2022 14:47 Q112 3 03-06-2022 15:18 03-06-2022 14:49 Q112 2 03-06-2022 15:21 03-06-2022 14:54 Q112 1 03-06-2022 15:20 03-06-2022 14:58 Q106 2 03-06-2022 15:23 03-06-2022 14:59 Q106 1
现有低效实现
循环方式
result = [] for i in range(0, len(df)): result.append(df[(df['Time_of_Fetch'] >= df.iloc[i]['Time_of_Fetch']) & (df['Time_of_Fetch'] < df.iloc[i]['Time_Completed']) & (df['Base'] == df.iloc[i]['Base'])].count()['Base']) df['Check_value'] = result
尝试的apply方法
df_108.assign = df_108.apply((lambda row :df_108[(df_108['Time_of_Fetch'] >= df_108['Time_of_Fetch']) & (df_108['Time_of_Fetch'] < df_108['Time_Completed'])& (df_108['Base'] == df_108['Base'])].count()['Base']),axis = 1)
以上两种方法时间复杂度均为O(n²),在大数据集下会因重复遍历数据导致耗时激增。
优化方案
核心思路
通过Base分组后,对每组的Time_of_Fetch排序,利用二分查找快速统计区间内的记录数,将时间复杂度降至O(N log N),大幅提升处理效率。
具体实现代码
步骤1:转换时间列为datetime类型
首先确保时间列是可比较的datetime格式:
import pandas as pd import bisect # 转换时间格式 df['Time_Completed'] = pd.to_datetime(df['Time_Completed'], format='%d-%m-%Y %H:%M') df['Time_of_Fetch'] = pd.to_datetime(df['Time_of_Fetch'], format='%d-%m-%Y %H:%M')
步骤2:分组+二分查找统计
使用向量化的二分查找实现,避免逐行遍历:
def count_in_range(group): # 对当前分组的Time_of_Fetch排序 sorted_times = group['Time_of_Fetch'].sort_values().values # 用二分查找计算每个区间的左右边界位置 left_positions = [bisect.bisect_right(sorted_times, t) for t in group['Time_of_Fetch']] right_positions = [bisect.bisect_left(sorted_times, t) for t in group['Time_Completed']] # 计算区间内的记录数 group['Check_value'] = [right - left + 1 for left, right in zip(left_positions, right_positions)] return group # 按Base分组处理,保留原索引顺序 df = df.groupby('Base', group_keys=False).apply(count_in_range)
方案优势
- 分组排序后,每组仅需一次排序(O(n log n)),后续二分查找为O(log n)每行
- 避免了原方法中对全数据集的重复过滤操作,大数据集下速度提升可达数十倍甚至上百倍
内容的提问来源于stack exchange,提问作者Praveen DA
相关产品推荐
相关产品推荐

