如何高效优化DataFrame中code列字符串转数值的逐行处理?
优化字符串转数值的高效处理方案
问题背景
给定如下DataFrame:
import pandas as pd df = pd.DataFrame({'code':['100M','60M10N40M','5S99M','1S25I100M','1D1S1I200M']})
需要将code列的字符串按规则转换为数值:
- M、N、D对应乘以1
- I对应乘以-1
- S对应乘以0
预期结果如下:
| code | Val | 计算逻辑 |
|---|---|---|
| 100M | 100 | (100*1) |
| 60M10N40M | 110 | (601)+(101)+(40*1) |
| 5S99M | 99 | (50)+(991) |
| 1S25I100M | 75 | (10)+(25-1)+(100*1) |
| 1D1S1I200M | 200 | (11)+(10)+(1*-1)+(200*1) |
原实现代码在大数据集下效率极低,耗时极久,需要优化:
import re def String2Val(String): # Generate substrings sstrings = re.findall('.[^A-Z]*.', String) KeyDict = {'M':'*1','N':'*1','I':'*-1','S':'*0','D':'*1'} newlist = [] for key, value in KeyDict.items(): for i in sstrings: if key in i: p = i.replace(key, value) lp = eval(p) newlist.append(lp) OutputVal = sum(newlist) return OutputVal df['Val'] = df.apply(lambda row: String2Val(row['code']), axis = 1)
原代码的效率瓶颈
eval函数拖累性能:eval会动态解析字符串,速度慢且存在安全风险,是核心性能瓶颈。- 逐行
apply未利用矢量化:df.apply(axis=1)本质是逐行遍历,完全浪费了pandas的矢量化计算优势,大数据集下会急剧变慢。 - 嵌套循环冗余:遍历字典键再遍历子字符串,重复检查匹配,存在不必要的计算开销。
- 正则表达式错误:原正则
.[^A-Z]*.无法正确拆分字符串(比如100M会被错误拆分),应该匹配数字+字母的标准模式。
优化方案
方案1:矢量化正则拆分 + 映射求和
利用正则拆分出每个数字与对应标识,通过映射系数快速计算总和:
import pandas as pd import re # 定义系数映射字典 coeff_map = {'M':1, 'N':1, 'I':-1, 'S':0, 'D':1} # 拆分每个code为(数字, 标识)的列表 df['parts'] = df['code'].apply(lambda x: re.findall(r'(\d+)([A-Z])', x)) # 计算每个列表的总和:数字*对应系数相加 df['Val'] = df['parts'].apply(lambda lst: sum(int(num)*coeff_map[char] for num, char in lst)) # 可选:删除临时列parts df = df.drop('parts', axis=1)
方案2:完全矢量化——explode+分组聚合
针对超大数据集,用explode展开拆分后的元素,批量计算后分组求和,彻底告别逐行遍历:
import pandas as pd import re coeff_map = {'M':1, 'N':1, 'I':-1, 'S':0, 'D':1} # 拆分字符串并生成展开后的DataFrame df_expanded = df['code'].str.extractall(r'(\d+)([A-Z])') df_expanded.columns = ['num', 'char'] df_expanded['num'] = df_expanded['num'].astype(int) df_expanded['coeff'] = df_expanded['char'].map(coeff_map) df_expanded['value'] = df_expanded['num'] * df_expanded['coeff'] # 按原行索引分组求和,合并回原DataFrame df['Val'] = df_expanded.groupby(level=0)['value'].sum()
方案3:批量表达式计算(安全替代eval)
如果偏好类似原逻辑的写法,可替换标识为系数表达式,用pd.eval批量计算(比逐行eval快数倍):
import pandas as pd coeff_map = {'M':'*1', 'N':'*1', 'I':'*-1', 'S':'*0', 'D':'*1'} # 将标识替换为乘法表达式,并用+连接 df['expr'] = df['code'] for char, expr in coeff_map.items(): df['expr'] = df['expr'].str.replace(char, f'{expr}+') # 移除末尾多余的+号 df['expr'] = df['expr'].str.rstrip('+') # 批量计算所有表达式 df['Val'] = pd.eval(df['expr'].tolist()) # 可选:删除临时列expr df = df.drop('expr', axis=1)
效率对比
- 原代码:逐行
apply+eval+嵌套循环,10万行数据耗时约数分钟。 - 方案1:用生成器配合
apply,耗时降至秒级。 - 方案2:完全矢量化操作,10万行数据耗时仅百毫秒级,是大数据集下的最优选择。
- 方案3:批量
pd.eval,效率接近方案2,代码更简洁直观。
内容的提问来源于stack exchange,提问作者newbzzs
相关产品推荐
相关产品推荐

