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

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

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

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

初始方法及性能瓶颈

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

import pandas as pdimport numpy as np# 示例DataFramedata = {'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_indexdf['prev'] = df.apply(get_most_recent_index, axis=1) print(df)

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

纳米搜索 纳米搜索

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

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

采用 bisect 模块实现高效查找

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

核心思想是:

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

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

from bisect import bisect_leftdef 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 =

以上就是Pandas DataFrame高效查找:定位满足条件的最近历史索引日期的详细内容,更多请关注创想鸟其它相关文章!

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 chuangxiangniao@163.com 举报,一经查实,本站将立刻删除。
发布者:程序猿,转转请注明出处:https://www.chuangxiangniao.com/p/567656.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2025年11月10日 04:18:51
下一篇 2025年11月10日 04:19:48

相关推荐

发表回复

登录后才能评论
关注微信