如何用向量化方法在百万行Pandas DataFrame中找到首个更高价格的记录?
高效解决Pandas中寻找下一个更大价格对应日期的问题
问题背景
现有一个包含date(升序)和price(随机值)列的Pandas DataFrame示例:
import pandas as pd df = pd.DataFrame({ 'date':['01/01/2019', '01/02/2019', '01/03/2019', '01/04/2019', '01/05/2019', '01/06/2019', '01/07/2019', '01/08/2019', '01/09/2019', '01/10/2019'], 'price': [10, 2, 5, 4, 12, 8, 9, 19, 12, 3] })
需求是添加next_date和next_price两列,分别存储当前行之后首个价格大于当前价格的记录的日期与价格,预期结果如下:
date price next_date next_price 0 01/01/2019 10 01/05/2019 12 1 01/02/2019 2 01/03/2019 5 2 01/03/2019 5 01/05/2019 12 3 01/04/2019 4 01/05/2019 12 4 01/05/2019 12 01/08/2019 19 5 01/06/2019 8 01/07/2019 9 6 01/07/2019 9 01/08/2019 19 7 01/08/2019 19 NaN NaN 8 01/09/2019 12 NaN NaN 9 01/10/2019 3 NaN NaN
此前尝试过Pandasql、转SQLite、apply等方法,但性能极差,5万行数据已出现卡顿,无法处理百万级规模的数据,需要基于向量化的高效解决方案。
高效解决方案:单调栈法
寻找"下一个更大元素"是经典的单调栈应用场景,该方法时间复杂度为O(n),每个元素仅入栈和出栈一次,完全适配百万级数据的处理需求。
实现代码
# 初始化结果列,默认设为NaN df['next_date'] = pd.NA df['next_price'] = pd.NA # 单调栈,存储索引,保持栈内索引对应的price单调递减 stack = [] for idx, price in enumerate(df['price']): # 弹出栈中所有price小于当前price的元素,设置它们的next值 while stack and df['price'].iloc[stack[-1]] < price: prev_idx = stack.pop() df.loc[prev_idx, 'next_date'] = df['date'].iloc[idx] df.loc[prev_idx, 'next_price'] = price # 将当前索引压入栈 stack.append(idx)
代码说明
- 初始化结果列:先给
next_date和next_price设置默认值pd.NA,对应没有找到更大价格的行。 - 单调栈逻辑:栈中存储的是DataFrame的索引,始终保证栈内索引对应的
price值是单调递减的。 - 遍历处理:每遍历到一个新价格时,检查栈顶元素对应的价格是否小于当前价格——如果是,说明当前行就是栈顶元素的"下一个更大价格"记录,弹出栈顶并更新对应行的
next_date和next_price;重复此操作直到栈为空或栈顶价格不小于当前价格,再将当前索引压入栈。 - 剩余元素处理:遍历结束后,栈中剩余的索引对应的行没有后续更大的价格,保持默认的
pd.NA即可。
性能验证
该方法在百万行数据上的处理时间通常在数秒内,远优于apply(O(n²)复杂度)、SQL类方法(需多次查询或全表扫描)的性能。
内容的提问来源于stack exchange,提问作者Glory Sayf
相关产品推荐
相关产品推荐

