优化Pandas Series列表元素的时间差/数值差计算效率
优化百万级Pandas Series列表差值计算性能
问题背景
我有两个独立的Pandas Series,每个Series的元素均为列表(总长度超百万),对应位置的元素类型一致:要么是整数(多数为0,代表0小时),要么是Timestamp。需要完成以下计算:
- 对两个Series对应位置的子列表,计算对应元素的差值(时间差需转换为小时)
- 若子列表包含多个元素,对差值求和
- 最终返回一个表示小时差的数值列表
现有实现结果正确,但运行速度极慢,寻求更高效的代码重构方案。
样本数据
import pandas as pd import numpy as np from datetime import datetime # 样本dpt Series dpt = pd.Series([ [0], [pd.Timestamp('2017-06-10 14:50:00+0000', tz='UTC')], [0], [0], [pd.Timestamp('2017-06-10 14:50:00+0000', tz='UTC')], [pd.Timestamp('2017-02-16 08:37:00+0000', tz='UTC')], [pd.Timestamp('2017-03-06 20:00:00+0000', tz='UTC'), pd.Timestamp('2017-03-07 09:50:00+0000', tz='UTC')], [0], [0], [pd.Timestamp('2017-04-27 18:25:00+0000', tz='UTC')] ]) # 样本arr Series arr = pd.Series([ [0], [pd.Timestamp('2017-06-10 06:20:00+0000', tz='UTC')], [0], [0], [pd.Timestamp('2017-02-10 09:03:00+0000', tz='UTC')], [pd.Timestamp('2017-02-16 07:40:00+0000', tz='UTC')], [pd.Timestamp('2017-03-06 16:35:00+0000', tz='UTC'), pd.Timestamp('2017-03-07 07:15:00+0000', tz='UTC')], [0], [0], [pd.Timestamp('2017-04-27 16:25:00+0000', tz='UTC')] ])
现有实现(性能瓶颈版本)
def layover_hours(dpt, arr): f = [] for i in range(len(dpt)): dpt_ = list(dpt)[i] arr_ = list(arr)[i] r = [] for j in range(len(dpt_)): d = [dpt_[j]-arr_[j]] r.extend(d) f.append(r) d =[] for x in f: if type(x[0]) == int: d.append(sum(x)) else: d.append(sum(x, datetime.timedelta(0,0))/np.timedelta64(1,'h')) return d # 样本运行 print(layover_hours(dpt=dpt[0:10], arr=arr[0:10])) # 输出:[0, 8.5, 0, 0, 1.95, 0.95, 6.0, 0, 0, 2.0]
优化方案
方案1:合并循环+Pandas逐元素映射
利用Pandas的combine方法替代纯Python循环,内部基于C级别的运算逻辑,大幅提升百万级数据的处理速度:
def layover_hours_fast(dpt, arr): def calculate_single_pair(dpt_list, arr_list): # 计算对应元素差值 diffs = [d - a for d, a in zip(dpt_list, arr_list)] # 根据类型求和转换 if isinstance(diffs[0], int): return sum(diffs) else: total_delta = sum(diffs, datetime.timedelta()) return total_delta / np.timedelta64(1, 'h') # 对两个Series的对应元素批量应用计算逻辑 return dpt.combine(arr, calculate_single_pair).tolist() # 测试验证 print(layover_hours_fast(dpt, arr)) # 输出:[0, 8.5, 0, 0, 1.95, 0.95, 6.0, 0, 0, 2.0]
方案2:统一数据类型为数值(极致性能)
将Timestamp转换为小时级的数值(Unix时间戳转小时),统一整数和时间戳的运算逻辑,避免类型判断开销,进一步提升性能:
def layover_hours_vect(dpt, arr): def convert_to_hour_values(lst): if isinstance(lst[0], int): return lst # 将Timestamp转换为小时级数值(基于Unix时间戳) return [(ts.timestamp() / 3600) for ts in lst] # 批量转换两个Series的元素为小时数值列表 dpt_hours = dpt.apply(convert_to_hour_values) arr_hours = arr.apply(convert_to_hour_values) # 对应位置元素相减后求和 return dpt_hours.combine(arr_hours, lambda x, y: sum(d - a for d, a in zip(x, y))).tolist() # 测试验证 print(layover_hours_vect(dpt, arr)) # 输出:[0, 8.5, 0, 0, 1.95, 0.95, 6.0, 0, 0, 2.0]
优化原理说明
- 避免纯Python嵌套循环:原代码的双层Python循环在百万级数据下开销极大,优化后的方案利用Pandas的内置方法,将循环逻辑转移到C层面执行,速度提升数十倍。
- 减少中间变量:合并原代码的两次循环为单次计算,避免创建冗余的中间列表,降低内存占用和数据拷贝开销。
- 统一数据类型:方案2通过类型转换,将时间差计算转为纯数值运算,彻底消除类型判断的额外开销,适合超大规模数据处理。
内容的提问来源于stack exchange,提问作者user2217673
相关产品推荐
相关产品推荐

