利用Pandas和NumPy高效筛选NaN附近有效数据的教程

碧海醫心
发布: 2025-11-10 12:16:01
原创
292人浏览过

利用Pandas和NumPy高效筛选NaN附近有效数据的教程

本教程探讨了在python中,如何高效地处理包含nan的数值数据,并为每个nan值智能地提取其前后指定数量的有效数值。文章将详细介绍如何结合使用pandas的ffill、numpy的sliding_window_view以及数据帧的join操作,以优雅且高效的方式实现这一复杂的数据筛选和选择逻辑,尤其适用于需要处理不规则数据缺失场景下的数据预处理任务。

在数据分析和预处理过程中,我们经常会遇到包含缺失值(NaN)的数值型数据。一个常见的需求是,当某个数据点为NaN时,我们需要从其周围提取固定数量的“有效”(非NaN)数值。这个任务的复杂性在于,有效数值可能不均匀分布在NaN点的前后,且提取过程中可能遇到其他的NaN值,需要灵活处理。传统的循环遍历方法效率低下,难以应对大规模数据集。本教程将介绍一种结合Pandas和NumPy的“巧妙”方法,以实现高效且灵活的NaN邻近有效数据筛选。

核心概念与工具

本解决方案主要依赖以下Pandas和NumPy的关键功能:

  1. pandas.Series.ffill() (Forward Fill):向前填充缺失值。在此方案中,它被巧妙地用于将最近的有效数据点的索引向前传播,为后续的滑动窗口操作提供对齐依据。
  2. numpy.lib.stride_tricks.sliding_window_view():创建一个滑动窗口视图。它可以在不复制数据的情况下,高效地生成数组的滑动窗口视图,这对于提取连续的子序列非常有用。关键在于,我们将此操作应用于已过滤掉NaN的有效数据序列。
  3. pandas.DataFrame.join():根据索引合并两个DataFrame。我们将利用它将原始数据与通过滑动窗口生成的邻近有效数据合并。

实现步骤详解

假设我们有一个包含NaN值的Pandas DataFrame,目标是为每个NaN值提取其前B个和后A个有效数值。

1. 准备示例数据

首先,我们创建一个示例DataFrame,其中包含一些NaN值,以便演示。

import pandas as pd
import numpy as np
from numpy.lib.stride_tricks import sliding_window_view as swv

# 示例数据
data = {
    'col': [np.nan, 0.0, 1.0, 2.0, np.nan, np.nan, 3.0, 4.0, 5.0, np.nan, 6.0, np.nan, 7.0, 8.0, 9.0, np.nan, 10.0]
}
df = pd.DataFrame(data)
print("原始数据:")
print(df)
登录后复制

2. 定义提取参数并识别有效数据

我们定义需要提取的有效数值数量:B 为NaN之前的数量,A 为NaN之后的数量。然后,从DataFrame中提取目标列,并创建一个布尔掩码来识别非NaN值。

B = 2  # NaN前需要提取的有效数值数量
A = 3  # NaN后需要提取的有效数值数量

# 提取目标列为Series,并确保索引是范围索引
s = df['col'].reset_index(drop=True)

# 识别非NaN行
m = s.notna()
登录后复制

3. 巧妙利用ffill对齐索引

这是解决方案中的一个关键步骤。我们首先将Series的索引转换为Series,然后使用where(m)将NaN值对应的索引替换为NaN,接着使用ffill()将这些NaN索引填充为它们前面最近的有效数值的原始索引。这个idx Series将成为我们后续对齐滑动窗口结果的桥梁。

# 掩盖NaN的索引,并用ffill向前填充,将NaN位置与最近的有效数值索引关联起来
idx = s.index.to_series().where(m).ffill()
登录后复制

现在,idx Series中的每个元素(除了开头连续的NaN)都指向其自身或其前面最近的有效数值的原始索引。

清程爱画
清程爱画

AI图像与视频生成平台,拥有超丰富的工作流社区和多种图像生成模式。

清程爱画 170
查看详情 清程爱画

4. 应用滑动窗口视图生成邻近数据

我们将sliding_window_view应用于只包含有效数值的Series (s[m])。这会生成一个多维数组,其中每一行都是一个滑动窗口。

# 在有效数值上应用滑动窗口视图
# A+B 是窗口大小
# 窗口的索引需要特殊处理,以与ffill后的idx对齐
tmp = pd.DataFrame(swv(s[m], A + B), 
                   index=idx[m].shift(-B + 1)[:m.sum() - (A + B) + 1])
登录后复制
  • swv(s[m], A + B):在过滤掉NaN的Series s[m] 上创建大小为 A+B 的滑动窗口。
  • index=idx[m].shift(-B + 1)[:m.sum() - (A + B) + 1]:这一步非常精巧。
    • idx[m]:获取有效数值对应的 idx 值。
    • .shift(-B + 1):将这些索引向后移动 B-1 个位置。这是为了将滑动窗口的起始点(即窗口中的第 B 个元素)与我们希望关联的NaN位置的 idx 值对齐。
    • [:m.sum() - (A + B) + 1]:截取索引,使其长度与滑动窗口视图 swv(s[m], A + B) 生成的行数匹配。

5. 重构与合并结果

最后,我们将滑动窗口结果tmp重新索引到idx Series,然后将其索引设置为原始DataFrame的索引,并使用mask(m)操作来清除原始数据中非NaN行对应的邻近数据(因为我们只关心NaN位置的邻近数据),最终通过join操作合并回原始DataFrame。

# 重新索引tmp到ffill后的idx,设置回原始df的索引,并掩盖掉原始数据非NaN行对应的结果
# 这样只有原始数据中为NaN的行,其新列才会有值
out = df.join(tmp.reindex(idx).set_axis(df.index).mask(m))

print("\n处理结果:")
print(out)
登录后复制

结果分析

运行上述代码,您将得到一个扩展的DataFrame:

原始数据:
     col
0    NaN
1    0.0
2    1.0
3    2.0
4    NaN
5    NaN
6    3.0
7    4.0
8    5.0
9    NaN
10   6.0
11   NaN
12   7.0
13   8.0
14   9.0
15   NaN
16  10.0

处理结果:
     col    0    1    2    3    4
0    NaN  NaN  NaN  NaN  NaN  NaN
1    0.0  NaN  NaN  NaN  NaN  NaN
2    1.0  NaN  NaN  NaN  NaN  NaN
3    2.0  NaN  NaN  NaN  NaN  NaN
4    NaN  1.0  2.0  3.0  4.0  5.0
5    NaN  1.0  2.0  3.0  4.0  5.0
6    3.0  NaN  NaN  NaN  NaN  NaN
7    4.0  NaN  NaN  NaN  NaN  NaN
8    5.0  NaN  NaN  NaN  NaN  NaN
9    NaN  4.0  5.0  6.0  7.0  8.0
10   6.0  NaN  NaN  NaN  NaN  NaN
11   NaN  5.0  6.0  7.0  8.0  9.0
12   7.0  NaN  NaN  NaN  NaN  NaN
13   8.0  NaN  NaN  NaN  NaN  NaN
14   9.0  NaN  NaN  NaN  NaN  NaN
15   NaN  NaN  NaN  NaN  NaN  NaN
16  10.0  NaN  NaN  NaN  NaN  NaN
登录后复制

观察输出结果:

  • 原始数据列 col 保持不变。
  • 新增了以 0, 1, 2, 3, 4 为列名的新列。这些列代表了每个NaN位置(如果存在)提取到的 B+A 个有效邻近值。
  • 对于原始数据中为NaN的行(例如索引4、5、9、11),新的列中会显示其对应的有效邻近值。例如,索引4和5的NaN,其前面两个有效值是1.0, 2.0,后面三个有效值是3.0, 4.0, 5.0,所以新列显示 1.0, 2.0, 3.0, 4.0, 5.0。
  • 对于原始数据中非NaN的行,新增的列则为NaN,因为我们只关心填充NaN位置。
  • 对于末尾的NaN(索引15),由于其后没有足够的有效值,因此新的列也显示为NaN。这表明该方法能够自动处理边界条件。

注意事项与优化

  • 参数 B 和 A 的含义: B 代表NaN“之前”所需的有效数值数量,A 代表NaN“之后”所需的有效数值数量。它们决定了滑动窗口的大小和提取的范围。
  • 性能: 此方法充分利用了NumPy的矢量化操作和 sliding_window_view 的视图特性(不复制数据),以及Pandas的优化内部实现,因此在大数据集上表现出优异的性能,远超基于Python循环的实现。
  • 灵活性: 通过简单地调整 B 和 A 的值,可以轻松改变提取邻近数据的策略。
  • 理解复杂性: 尽管代码相对简洁,但理解 idx 的生成逻辑、sliding_window_view 的索引对齐以及 mask(m) 的作用是掌握此方法的关键。它巧妙地将原始索引、有效数据索引和滑动窗口结果关联起来。
  • 边界条件处理: 当NaN位于数据序列的开头或结尾,或者其周围没有足够的有效数值时,sliding_window_view 的结果会相应减少,并且最终的 join 操作会正确地填充NaN,表示无法获取足够的邻近数据。

总结

本教程介绍了一种在Python中利用Pandas和NumPy高效处理NaN值并提取其邻近有效数据的专业方法。通过结合 pandas.Series.ffill()、numpy.lib.stride_tricks.sliding_window_view() 和 pandas.DataFrame.join(),我们能够以一种矢量化、高性能的方式解决这一常见的数据预处理挑战。这种方法不仅代码简洁,而且能够优雅地处理各种复杂的边界条件和NaN分布情况,是数据科学家和工程师在处理不规则缺失数据时的有力工具。

以上就是利用Pandas和NumPy高效筛选NaN附近有效数据的教程的详细内容,更多请关注php中文网其它相关文章!

最佳 Windows 性能的顶级免费优化软件
最佳 Windows 性能的顶级免费优化软件

每个人都需要一台速度更快、更稳定的 PC。随着时间的推移,垃圾文件、旧注册表数据和不必要的后台进程会占用资源并降低性能。幸运的是,许多工具可以让 Windows 保持平稳运行。

下载
来源:php中文网
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn
最新问题
开源免费商场系统广告
热门教程
更多>
最新下载
更多>
网站特效
网站源码
网站素材
前端模板
关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新 English
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送
PHP中文网APP
随时随地碎片化学习

Copyright 2014-2025 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号