
本教程探讨了在python中,如何高效地处理包含nan的数值数据,并为每个nan值智能地提取其前后指定数量的有效数值。文章将详细介绍如何结合使用pandas的ffill、numpy的sliding_window_view以及数据帧的join操作,以优雅且高效的方式实现这一复杂的数据筛选和选择逻辑,尤其适用于需要处理不规则数据缺失场景下的数据预处理任务。
在数据分析和预处理过程中,我们经常会遇到包含缺失值(NaN)的数值型数据。一个常见的需求是,当某个数据点为NaN时,我们需要从其周围提取固定数量的“有效”(非NaN)数值。这个任务的复杂性在于,有效数值可能不均匀分布在NaN点的前后,且提取过程中可能遇到其他的NaN值,需要灵活处理。传统的循环遍历方法效率低下,难以应对大规模数据集。本教程将介绍一种结合Pandas和NumPy的“巧妙”方法,以实现高效且灵活的NaN邻近有效数据筛选。
核心概念与工具
本解决方案主要依赖以下Pandas和NumPy的关键功能:
pandas.Series.ffill() (Forward Fill):向前填充缺失值。在此方案中,它被巧妙地用于将最近的有效数据点的索引向前传播,为后续的滑动窗口操作提供对齐依据。numpy.lib.stride_tricks.sliding_window_view():创建一个滑动窗口视图。它可以在不复制数据的情况下,高效地生成数组的滑动窗口视图,这对于提取连续的子序列非常有用。关键在于,我们将此操作应用于已过滤掉NaN的有效数据序列。pandas.DataFrame.join():根据索引合并两个DataFrame。我们将利用它将原始数据与通过滑动窗口生成的邻近有效数据合并。
实现步骤详解
假设我们有一个包含NaN值的Pandas DataFrame,目标是为每个NaN值提取其前B个和后A个有效数值。
1. 准备示例数据
首先,我们创建一个示例DataFrame,其中包含一些NaN值,以便演示。
import pandas as pdimport numpy as npfrom 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)都指向其自身或其前面最近的有效数值的原始索引。
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:
原始数据: col0 NaN1 0.02 1.03 2.04 NaN5 NaN6 3.07 4.08 5.09 NaN10 6.011 NaN12 7.013 8.014 9.015 NaN16 10.0处理结果: col 0 1 2 3 40 NaN NaN NaN NaN NaN NaN1 0.0 NaN NaN NaN NaN NaN2 1.0 NaN NaN NaN NaN NaN3 2.0 NaN NaN NaN NaN NaN4 NaN 1.0 2.0 3.0 4.0 5.05 NaN 1.0 2.0 3.0 4.0 5.06 3.0 NaN NaN NaN NaN NaN7 4.0 NaN NaN NaN NaN NaN8 5.0 NaN NaN NaN NaN NaN9 NaN 4.0 5.0 6.0 7.0 8.010 6.0 NaN NaN NaN NaN NaN11 NaN 5.0 6.0 7.0 8.0 9.012 7.0 NaN NaN NaN NaN NaN13 8.0 NaN NaN NaN NaN NaN14 9.0 NaN NaN NaN NaN NaN15 NaN NaN NaN NaN NaN NaN16 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附近有效数据的教程的详细内容,更多请关注创想鸟其它相关文章!
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 chuangxiangniao@163.com 举报,一经查实,本站将立刻删除。
发布者:程序猿,转转请注明出处:https://www.chuangxiangniao.com/p/1379021.html
微信扫一扫
支付宝扫一扫