如何将含整数、带M后缀字符串的列转为整数(保留np.NaN)
问题描述
现有一个Pandas列x1,数据包含整数、np.NaN以及带MMM/MMMM后缀的字符串,示例数据如下:
x1 ___ 128455551 92571902 123125 985166 np.NaN 2241 1.50000MMM 2.5255MMM 1.2255MMMM np.NaN ...
需求如下:
- 带
MMM的行:去除后缀后将数值乘以10**9转为整数 - 带
MMMM的行:去除后缀后乘以10**12转为整数 - 必须保留
np.NaN
转换后预期结果:
x1 ___ 128455551 92571902 123125 985166 np.NaN 2241 1500000000 2525500000 1225500000000 np.NaN ...
尝试了以下代码:
df['x1'] = np.where(df.x1.astype(str).str.contains('MMM'), (df.x1.str.replace('MMM', '').astype(float) * 10**9).astype(int), df.x1)
单独处理两行时有效,但处理整个DataFrame时出现错误:
IntCastingNaNError: Cannot convert non-finite values (NA or inf) to integer
解决方案
错误原因
- 原代码未区分
MMMM和MMM的处理逻辑,会导致MMMM被误处理; - Pandas普通整数类型(
int)无法存储NaN,混合整数、NaN和转换后数值时,类型冲突引发报错; - 整列操作时
np.where返回的数组包含多种类型(字符串、整数、NaN),后续类型转换逻辑混乱。
方案一:自定义函数+可空整数类型
用自定义函数逐个处理元素,结合Pandas的**可空整数类型(Int64,大写I)**实现需求,逻辑清晰易维护:
import pandas as pd import numpy as np def convert_x1(val): if pd.isna(val): return pd.NA val_str = str(val) if 'MMMM' in val_str: num = float(val_str.replace('MMMM', '')) * 10**12 return int(num) elif 'MMM' in val_str: num = float(val_str.replace('MMM', '')) * 10**9 return int(num) else: return int(val) # 应用函数并转换为可空整数类型 df['x1'] = df['x1'].apply(convert_x1).astype('Int64')
方案二:向量化操作(大数据集推荐)
如果数据量较大,用向量化操作替代apply,性能更优:
import pandas as pd import numpy as np # 转为字符串统一处理后缀 x1_str = df['x1'].astype(str) # 标记各类数据的位置 is_mmmm = x1_str.str.contains('MMMM') is_mmm = x1_str.str.contains('MMM') & ~is_mmmm is_nan = df['x1'].isna() # 初始化结果列为可空整数类型 df['x1'] = pd.Series(pd.NA, index=df.index, dtype='Int64') # 批量处理各类数据 df.loc[is_mmmm, 'x1'] = (x1_str[is_mmmm].str.replace('MMMM', '').astype(float) * 10**12).astype(int) df.loc[is_mmm, 'x1'] = (x1_str[is_mmm].str.replace('MMM', '').astype(float) * 10**9).astype(int) non_suffix_rows = ~is_mmmm & ~is_mmm & ~is_nan df.loc[non_suffix_rows, 'x1'] = df['x1'][non_suffix_rows].astype(int)
关键说明
Int64可空整数类型允许列中同时存在整数和NaN,解决了普通整数类型无法存储缺失值的问题;- 必须先处理
MMMM再处理MMM,避免长后缀被误匹配; - 向量化操作通过批量处理替代逐行循环,适合百万级以上数据集。
内容的提问来源于stack exchange,提问作者anarchy
相关产品推荐
相关产品推荐

