
本文详解为何 str.extract() 在未使用 raw string 时会丢失小数位,并提供带完整示例的解决方案,确保 GPA 等浮点型字符串被准确解析为保留原始精度的数值。
本文详解为何 `str.extract()` 在未使用 raw string 时会丢失小数位,并提供带完整示例的解决方案,确保 gpa 等浮点型字符串被准确解析为保留原始精度的数值。
在数据清洗过程中,常需从混杂文本(如 '3.654'、'3.79 btch'、'Personal ')中提取有效数字。你遇到的问题——所有 GPA 值最终变成 2.0、3.0、4.0(整数形式),根本原因在于正则表达式中的反斜杠 \d 和 \. 未被 Python 正确识别:普通字符串中 \. 会被解释为「任意字符」(. 的转义失效),而 \d 可能被误解析为 ASCII 控制字符(如 \x0d),导致正则匹配行为异常,仅捕获到最左侧的单个数字(如 '3.654' 中只匹配 '3'),后续 pd.to_numeric() 将其转为 3.0。
✅ 正确做法是使用 raw string(原始字符串),即在正则前加 r 前缀,使反斜杠按字面意义传递给正则引擎:
# ✅ 正确:使用 raw string 确保 \d 和 \. 被正则引擎正确解析 food['GPA'] = food['GPA'].astype(str).str.extract(r'(\d*\.\d+|\d+)', expand=False) food['GPA'] = pd.to_numeric(food['GPA'], errors='coerce')
该正则 r'(\d*\.\d+|\d+)' 含两部分逻辑:
-
\d*\.\d+:匹配零个或多个数字 + 字面量小数点 + 一个及以上数字 → 捕获3.654、.75(若存在)、0.5 -
\d+:匹配一个及以上数字 → 捕获4、3、2等整数
二者用|表示“或”,确保覆盖所有数值格式。
? 验证效果:
print(food['GPA'].unique()) # 输出示例(保留原始精度): # [2.4 3.654 3.3 3.2 3.5 2.25 3.8 3.904 3.4 3.6 3.1 nan # 4. 2.2 3.87 3.7 3.9 2.8 3. 3.65 3.89 2.9 3.605 3.83 # 3.292 3.35 2.6 3.67 3.73 3.79 2.71 3.68 3.75 3.92 3.77 3.63 3.882]
⚠️ 注意事项:
-
errors='coerce'是关键:将无法转换的值(如'Personal '、'Unknown')安全转为NaN,避免报错; - 若数据中存在科学计数法(如
'1e-2')或负数(如'-3.5'),需扩展正则:r'(-?\d*\.?\d+(?:e[+-]?\d+)?)'; - 提取前强制
.astype(str)可防止nan引发AttributeError(因np.nan无.str属性); - 建议清洗后检查
food['GPA'].isna().sum(),确认异常值处理符合预期。
通过这一修正,你不仅能恢复全部小数精度,也为后续统计分析(如均值、分布可视化)奠定准确的数据基础。











