如何在 Pandas 中识别并移除“孤立值”(即前后均为缺失值的非空单元格)

5次阅读

如何在 Pandas 中识别并移除“孤立值”(即前后均为缺失值的非空单元格)

本文介绍一种基于 shift() 的高效方法,用于识别并清空 DataFrame 中满足“前一行和后一行均为 NaN”的孤立非空值,适用于清洗时序或结构化数据中的噪声点。

本文介绍一种基于 `shift()` 的高效方法,用于识别并清空 dataframe 中满足“前一行和后一行均为 nan”的孤立非空值,适用于清洗时序或结构化数据中的噪声点。

在数据预处理中,常遇到一类特殊噪声:某个非空值被上下两个缺失值(NaN)完全包围,形成“孤立峰”。这类值往往缺乏上下文支撑,可能源于采集异常、传输错误或标注疏漏。pandas 本身不提供直接的“孤立值检测”函数,但可通过行偏移(shift)配合布尔索引精准定位并清理。

核心思路是:对目标列分别获取其前一行(shift(1))与后一行(shift(-1))的值,再判断当前行是否非空,且前后行同时为空——满足该条件的单元格即为“孤立值”,应置为 None(或 np.nan)。

以下为完整实现示例:

import pandas as pd import numpy as np  # 构造原始 DataFrame(模拟问题场景) df = pd.DataFrame({     "A": [np.nan, 1, np.nan, 1, 1, 1, 1],     "B": [1, 1, np.nan, 1, np.nan, 1, 1] })  print("原始 DataFrame:") print(df)

输出:

A    B 0  NaN  1.0 1  1.0  1.0 2  NaN  NaN 3  1.0  1.0 4  1.0  NaN 5  1.0  1.0 6  1.0  1.0

现在对列 “A” 执行孤立值识别与清除:

# 步骤1:生成前后行参考列 df["A_prev"] = df["A"].shift(1)   # 前一行值(第0行对应 NaN) df["A_next"] = df["A"].shift(-1)  # 后一行值(最后一行对应 NaN)  # 步骤2:定义“孤立”逻辑:当前非空 & 前空 & 后空 is_isolated_A = df["A"].notna() & df["A_prev"].isna() & df["A_next"].isna()  # 步骤3:原地修改 — 将孤立值设为 NaN df.loc[is_isolated_A, "A"] = np.nan  # 可选:清理辅助列 df = df.drop(columns=["A_prev", "A_next"])  print("n处理后的 DataFrame(列 A 已清除孤立值):") print(df)

输出:

A    B 0  NaN  1.0 1  NaN  1.0   ← 原值 1 被清除(因前后均为 NaN) 2  NaN  NaN 3  1.0  1.0 4  1.0  NaN 5  1.0  1.0 6  1.0  1.0

同理,可对 “B” 列应用相同逻辑(只需替换列名),或封装为通用函数提升复用性:

def remove_isolated_values(df, columns, inplace=False):     """     清除指定列中前后均为 NaN 的孤立非空值      Parameters:     -----------     df : pd.DataFrame     columns : str or list of str     inplace : bool, default False     """     if not isinstance(columns, list):         columns = [columns]      df_target = df if inplace else df.copy()      for col in columns:         if col not in df_target.columns:             continue         prev = df_target[col].shift(1)         nxt = df_target[col].shift(-1)         mask = df_target[col].notna() & prev.isna() & nxt.isna()         df_target.loc[mask, col] = np.nan      return df_target  # 一键处理多列 df_clean = remove_isolated_values(df, columns=["A", "B"])

⚠️ 注意事项

  • 边界行为:首行无“前一行”,末行无“后一行”,其对应 shift 结果恒为 NaN,因此首尾行不可能被判定为孤立值(除非本身为 NaN),符合直觉;
  • 数据类型:shift() 对 Object 类型列同样有效,但需确保缺失值统一为 None 或 np.nan(推荐使用 pd.NA 配合 Nullable 类型以获得更健壮行为);
  • 性能:该方法为向量化操作,时间复杂度 O(n),远优于循环遍历,适合万级至百万级数据;
  • 扩展性:如需“容忍一个邻近非空值”,可改为 prev.isna() | nxt.isna() 等逻辑组合,灵活适配业务规则。

通过此方法,你不仅能精准剔除结构化数据中的孤立噪声点,还能保持原始索引与行列结构不变,为后续分析提供更干净、可信的数据基础。

text=ZqhQzanResources