
本文介绍在 Pandas 中正确识别并替换以字符串形式“以 -9 开头”的数值(如 -9.0、-99.0、-9.678)为 NaN 的完整方法,重点解决因数据类型为 float 导致正则失效的问题,并提供安全、可复现的操作步骤。
本文介绍在 Pandas 中正确识别并替换以字符串形式“以 -9 开头”的数值(如 -9.0、-99.0、-9.678)为 NaN 的完整方法,重点解决因数据类型为 float 导致正则失效的问题,并提供安全、可复现的操作步骤。
在处理气象、传感器或调查类数据时,常使用 -9、-99、-999 等作为缺失值标记(即“哨兵值”)。但若这些值被 Pandas 自动解析为浮点数(如 float64),直接对数值应用正则表达式(如 regex='^-9.*')将完全无效——因为正则仅作用于字符串,而 19.5 和 -9.0 在数值层面都是 float,无法通过字符串前缀匹配。
✅ 正确思路是:先确保目标列以字符串形式存在,再用正则精准匹配以 "-9" 开头的字符串,最后统一转为 NaN。
以下是推荐的三步实现方案(兼顾鲁棒性与可读性):
✅ 方法一:加载阶段指定 dtype=str(最优实践)
若数据来自 CSV/Excel,应在读取时统一设为字符串,避免后续类型转换隐患:
import pandas as pd
import numpy as np
# 读取时强制所有列(或指定列)为 string
weatherData_original = pd.read_csv("weather.csv", dtype=str)
# 或仅对数值列设为 str(更精细控制):
# weatherData_original = pd.read_csv("weather.csv", dtype={"Solar": str, "MaxRH": str, "AvgAirTemp": str})
# 然后执行正则替换(注意:^ 表示行首,-9 后可接任意数字/小数点/数字)
new_df = weatherData_original.replace(regex=r'^-9\.?\d*$', value=np.nan)
? 正则说明:
r'^-9\.?\d*$'
^:字符串开头-9:字面量 "-9"\.?:可选的小数点(匹配-9和-9.)\d*:零个或多个数字(匹配-9,-90,-9.678)$:字符串结尾 → 确保完整匹配,避免误伤19.5或-19.2
✅ 方法二:运行时临时转字符串(适用于已加载的 float 数据)
若数据已加载且含 float64 类型,需逐列转换并替换:
# 创建副本,避免修改原数据
new_df = weatherData_original.copy()
# 定义需处理的数值列(排除 'Date' 等非数值列)
numeric_cols = ["Solar", "MaxRH", "AvgAirTemp"] # 根据实际列名调整
for col in numeric_cols:
if col in new_df.columns:
# 转为字符串 → 替换 → 转回数值(NaN 自动保留)
new_df[col] = (new_df[col]
.astype(str)
.replace(r'^-9\.?\d*$', np.nan, regex=True)
.astype(float)) # 自动将 'nan' 字符串转为 float64 NaN
⚠️ 注意事项与常见误区
- ❌
regex=r'^-9\d+'无法匹配-9.678(\d+不匹配小数点); - ❌
regex='^[-9].*'是错误写法:[-9]表示“匹配字符 - 或 9”,会误杀9.5、-1.2等; - ❌
pd.NA与np.nan区别:pd.NA需配合nullable integer或stringdtype;科学计算中推荐np.nan(兼容float64); - ✅ 替换后建议验证:
new_df[["Solar", "MaxRH", "AvgAirTemp"]].isna().sum()查看各列 NaN 数量是否符合预期。
✅ 最终效果(基于示例数据)
# 原始片段(float 类型): # Solar MaxRH AvgAirTemp # 0 -9.00 -9.0 -99.00 # 1 -9.00 -9.0 0.31 # 处理后: # Solar MaxRH AvgAirTemp # 0 NaN NaN NaN # 1 NaN NaN 0.31
掌握“类型先行”原则——正则操作必须在字符串上下文中进行——是高效清洗哨兵值的关键。优先在数据摄入阶段控制 dtype,可大幅降低后期处理复杂度与出错风险。










