推荐用 str.extract(r'([-+]?\d*.?\d+(?:eE?\d+)?)') 提取合法数值片段,再经清洗和 pd.to_numeric(..., errors='coerce') 转 float;单位需单独提取并标准化,避免丢失信息或误解析。

识别并提取数值部分的正则模式
带单位的字符串(如 "12.5kg"、"3.2m/s"、"100%")不能直接转为数字,pd.to_numeric() 会报 ValueError: Unable to parse string。关键不是“去掉所有非数字字符”,而是保留小数点、负号、科学计数法符号(e/E),同时剥离单位前缀或后缀。
推荐用 str.extract(r'([\-+]?\d*\.?\d+(?:[eE][\-+]?\d+)?)') —— 它能捕获带符号、小数、指数的合法数值片段,且不贪婪匹配后续单位。比 str.replace(r'[^0-9.-eE]', '') 更安全,后者可能把 "10e2m" 错变成 "10e2"(看似对,但若原意是 10 × 10² 米,其实应保留为 1000,而该正则无法自动做单位换算)。
常见错误:用 str.split() 或 str.strip() 硬切,遇到 "5.5 kg"(空格分隔)和 "5.5kg"(无空格)就失效。
处理含空格、括号、多单位的混合字符串
真实数据常含干扰符,例如 "(24.8 lbs)"、"~30 km/h"、"120±5 g"。单一正则难覆盖全部,需分层清理:
立即学习“Python免费学习笔记(深入)”;
- 先用
str.replace(r'[()~±]', ' ')统一替换干扰符号为空格 - 再用
str.split().str[0]取首个疑似数值字段(适用于前缀型干扰) - 最后用前述
str.extract()提取纯数值 —— 这步必须放在去干扰之后,否则括号里的数字(如"(10) kg")会被忽略
注意:str.extract() 默认返回 Series,若原列有缺失值,结果会是 NaN;若想保留原始索引对齐,别漏掉 expand=False 参数(虽然此处单组捕获无需设)。
单位标准化与数值转换后的类型控制
提取出的字符串仍是 object 类型,需显式转 float。但直接 astype(float) 遇到空字符串或全空格会报错,必须前置清洗:
- 用
str.strip().replace('', np.nan)清除空白并转空值 - 再用
pd.to_numeric(..., errors='coerce')容错转换 —— 比astype(float)更鲁棒 - 若原始单位不统一(如列中混有
"kg"和"g"),提取数值后需额外映射:构建字典{'kg': 1000, 'g': 1, 'mg': 0.001},再按对应单位列乘系数
性能提示:避免链式调用多次 str.xxx(),可合并为单次 apply() 自定义函数,尤其当数据量 >10⁵ 行时,向量化操作快 3–5 倍。
保留原始单位信息用于后续校验
单纯丢弃单位容易掩盖数据质量问题。建议新增一列存单位,用 str.extract(r'([a-zA-Z%/]+)$') 提取末尾单位($ 确保是结尾),再配合 str.strip() 去空格。这样既能做数值计算,又可检查异常单位(如某列本该是 "cm" 却出现 "in")。
容易被忽略的是:某些单位本身含数字,如 "10kW" 中的 k 是千进制前缀,不应被当作单位主体提取。此时需在单位提取正则中排除 k、M、G 等 SI 前缀,或优先在数值提取阶段把它们纳入系数换算逻辑。


















