单调时序DataFrame偏移匹配优化:提速及最近邻匹配需求
问题描述
现有一个含单调时序ts的DataFrame,结构如下:
ts | value1 | value2 11 9 x 19 10 x 26 x x 29 x x 32 x x
需求为:对每个value1,找到x秒前刚好超过计算时间点(ts-x)的value2。示例:当x=10时,32-10=22,刚好超过22的ts为26,取该点的value2;29-10=19,对应ts=19,取该点的value2。
本人编写了如下O(n)复杂度的循环代码,但运行速度极慢:
x = 10 i1 = 0 row_num = df.shape[0] for i in range(row_num): cur_row = df.iloc[i] cur_t = cur_row.ts cur_v = cur_row.value1 delay_t = cur_t - x while i1 < row_num and df.iloc[i1].ts < delay_t: i1 += 1 delay_v = df.iloc[i1].value2 df.iloc[i,3] = cur_v - delay_v
现咨询两个问题:
- 该代码运行缓慢的原因是什么?如何优化?优先采用向量化实现。
- 若能解决第一个问题,能否进一步优化为找到最接近
ts-x的value2?例如32-10=22,比较19和26与22的距离,取ts=19对应的value2。
问题解答
1. 代码慢的原因与向量化优化
慢的核心原因
算法本身是O(n)复杂度,但循环中反复调用df.iloc[i]属于逐行操作,Pandas的行级读取会频繁触发数据定位和对象创建,带来大量额外开销;同时直接在循环中修改df.iloc[i,3],也不符合DataFrame的批量优化设计,导致实际运行效率极低。
向量化优化方案
利用Pandas内置的searchsorted方法,它针对有序序列做二分查找(单查询O(logn),整体O(nlogn)),全程向量化操作,速度远快于循环:
import pandas as pd x = 10 # 计算每个时间点对应的延迟目标时间 df['delay_t'] = df['ts'] - x # 找到每个delay_t对应的第一个>=它的ts的索引 target_indices = df['ts'].searchsorted(df['delay_t'], side='left') # 提取对应value2并计算结果 df['delay_v'] = df['value2'].iloc[target_indices].values df['result'] = df['value1'] - df['delay_v']
如果ts是严格单调递增的,该方案完全匹配需求,且性能比原始循环提升几个数量级。
2. 查找最接近ts-x的value2
通过searchsorted分别获取延迟时间的左、右插入点,再比较两个相邻点与目标时间的距离,选择更近的那个:
x = 10 df['delay_t'] = df['ts'] - x # 获取左(第一个>=delay_t)、右(第一个>delay_t)插入点 left_indices = df['ts'].searchsorted(df['delay_t'], side='left') right_indices = df['ts'].searchsorted(df['delay_t'], side='right') # 遍历处理边界与距离比较 final_indices = [] for idx, dt in enumerate(df['delay_t']): left = left_indices[idx] right = right_indices[idx] if left == 0: final_indices.append(0) elif right == len(df): final_indices.append(len(df)-1) else: dist_left = dt - df['ts'].iloc[left-1] dist_right = df['ts'].iloc[right] - dt final_indices.append(left-1 if dist_left <= dist_right else right) # 提取对应value2并计算结果 df['closest_v'] = df['value2'].iloc[final_indices].values df['closest_result'] = df['value1'] - df['closest_v']
该方案仅在最后一步做少量循环处理边界,核心查找逻辑仍用向量化的searchsorted,整体效率依然远高于原始循环。
内容的提问来源于stack exchange,提问作者YNX
相关产品推荐
相关产品推荐

