值得一看
广告
彩虹云商城
广告

热门广告位

Pandas DataFrame高效查找:定位满足条件的最近历史索引日期

pandas dataframe高效查找:定位满足条件的最近历史索引日期

本教程探讨如何在Pandas DataFrame中高效地为每一行查找满足特定条件(如`lower >= upper`)的最近历史行索引(日期)。针对传统`df.apply`方法的低效性,文章重点介绍并演示了如何利用Python内置的`bisect`模块实现高性能查找,并简要提及其他优化尝试,最终旨在提供一种处理此类依赖历史状态问题的最佳实践。

在数据分析和处理中,我们经常会遇到需要基于当前行之前的历史数据来计算新列的场景。一个典型的例子是,对于DataFrame中的每一行,我们需要找到一个特定条件(例如,某一列的值大于或等于另一列的值)在之前行中最后一次满足时的索引(通常是日期时间索引)。然而,直接使用Pandas的apply方法进行逐行操作,尤其是在大数据集上,效率会非常低下。

初始方法及性能瓶颈

考虑以下场景:我们有一个包含lower和upper两列的DataFrame,并以日期作为索引。目标是创建一个新列prev,其中包含满足 lower >= upper 条件的最近历史行的日期索引。

import pandas as pd
import numpy as np
# 示例DataFrame
data = {'lower': [7, 1, 6, 1, 1, 1, 1, 11, 1, 1],
'upper': [2, 3, 4, 5, 6, 7, 8, 9, 10, 11]}
df = pd.DataFrame(data=data)
df['DATE'] = pd.date_range('2020-01-01', periods=len(data['lower']))
df['DATE'] = pd.to_datetime(df['DATE'])
df.set_index('DATE', inplace=True)
# 使用 df.apply 的原始方法
def get_most_recent_index(row):
# 查找当前行之前的所有行
previous_indices = df.loc[:row.name - pd.Timedelta(minutes=1)]
# 筛选满足条件的行,并获取最大的索引(即最近的日期)
recent_index = previous_indices[previous_indices['lower'] >= row['upper']].index.max()
return recent_index
df['prev'] = df.apply(get_most_recent_index, axis=1)
print(df)

上述代码中的get_most_recent_index函数通过df.loc对DataFrame进行切片,然后进行条件筛选,最后获取最大索引。这种方法的问题在于:

纳米搜索

纳米搜索

纳米搜索:360推出的新一代AI搜索引擎

纳米搜索
30

查看详情
纳米搜索

  1. 逐行迭代: df.apply(axis=1)本质上是Python级别的循环,效率远低于Pandas或NumPy的向量化操作。
  2. 重复切片与筛选: 每一行都会对DataFrame进行一次切片和条件筛选,对于大型DataFrame,这会导致大量的重复计算和内存操作。
    在一个包含100,000行的DataFrame上,这种方法的执行时间可能长达数分钟,这在实际应用中是难以接受的。

采用 bisect 模块实现高效查找

为了显著提升性能,我们可以利用Python内置的bisect模块。bisect模块提供了二分查找算法,可以在已排序的序列中快速定位元素。虽然这个问题并非完全向量化,但通过巧妙地结合bisect和字典来维护历史状态,可以实现准线性时间复杂度的解决方案。

核心思想是:

  1. 维护一个已排序的、不重复的lower值列表 (uniq_lower)。
  2. 维护一个字典last_seen,记录每个lower值最后一次出现的日期。
  3. 对于DataFrame中的每一行,我们需要找到所有满足 l >= current_upper 的 l 值,并从 last_seen 中找出这些 l 值对应的最大日期。

以下是使用bisect模块的优化实现:

from bisect import bisect_left
def get_prev_bs(lower_series, upper_series, date_index):
# 获取所有不重复的 lower 值并排序
uniq_lower = sorted(set(lower_series))
# 存储每个 lower 值最后一次出现的日期
last_seen = {}
# 迭代 DataFrame 的每一行
for l, u, d in zip(lower_series, upper_series, date_index):
# 使用 bisect_left 找到第一个大于或等于当前 upper 值的 lower 值的索引
# 这意味着 uniq_lower[idx:] 包含了所有 >= u 的 lower 值
idx = bisect_left(uniq_lower, u)
max_date = None
# 遍历所有满足条件的 lower 值
for lv in uniq_lower[idx:]:
if lv in last_seen:
# 如果该 lower 值在历史中出现过
if max_date is None:
max_date =
相关标签:

python 大数据 app 性能瓶颈 Python numpy pandas 循环 切片 算法 数据分析

大家都在看:

python变量中self的添加
如何检查电脑是否已安装Python_检查电脑Python版本及安装状态的多种方法
Python多线程计算一元二次方程根的常见问题与解决方案
Python Hangman游戏开发:解决字符串操作与逻辑错误
Python循环中条件判断与用户输入验证的正确姿势
温馨提示: 本文最后更新于2025-11-05 16:31:35,某些文章具有时效性,若有错误或已失效,请在下方留言或联系在线客服
文章版权声明 1 本网站名称: 创客网
2 本站永久网址:https://new.ie310.com
1 本文采用非商业性使用-相同方式共享 4.0 国际许可协议[CC BY-NC-SA]进行授权
2 本站所有内容仅供参考,分享出来是为了可以给大家提供新的思路。
3 互联网转载资源会有一些其他联系方式,请大家不要盲目相信,被骗本站概不负责!
4 本网站只做项目揭秘,无法一对一教学指导,每篇文章内都含项目全套的教程讲解,请仔细阅读。
5 本站分享的所有平台仅供展示,本站不对平台真实性负责,站长建议大家自己根据项目关键词自己选择平台。
6 因为文章发布时间和您阅读文章时间存在时间差,所以有些项目红利期可能已经过了,能不能赚钱需要自己判断。
7 本网站仅做资源分享,不做任何收益保障,创业公司上收费几百上千的项目我免费分享出来的,希望大家可以认真学习。
8 本站所有资料均来自互联网公开分享,并不代表本站立场,如不慎侵犯到您的版权利益,请联系79283999@qq.com删除。

本站资料仅供学习交流使用请勿商业运营,严禁从事违法,侵权等任何非法活动,否则后果自负!
THE END
喜欢就支持一下吧
点赞9赞赏 分享
评论 抢沙发

请登录后发表评论

    暂无评论内容