处理2400万条记录的Python pandas代码无法运行原因及性能优化
问题原因
pandas.Series.apply本身是纯Python层的逐行迭代,2400万次函数调用的开销极高,没有利用到向量化运算的性能优势。- 自定义函数本身存在大量冗余逻辑,性能损耗严重:
- 手动遍历字符串每个字符计数取奇数索引位,完全可以用Python原生字符串切片代替
- 循环内每次命中奇数索引位都执行
string_even = "".join(list_even),相当于每次都重新生成一次字符串,时间复杂度提升到O(n²),字符串越长速度越慢 abs(ord(letter)-3) < 1114111是无效判断,Unicode的ord返回值最大为1114111,运算结果永远满足条件,属于无效计算
- 单进程运行没有利用到7核CPU的多核性能,硬件资源浪费
优化方案
第一步:优化自定义函数逻辑
先把冗余逻辑全部删掉,用原生字符串操作重写,性能可提升10~100倍:
def separate_string_opt(sentence): if sentence is None: return "" # 切片直接取奇数索引位字符,无需手动遍历计数 odd_chars = sentence[1::2] # 直接生成转换后的字符串,去掉无效判断和冗余join return "".join(chr(abs(ord(c) - 3)) for c in odd_chars)
如果追求更高性能,可以加numba JIT编译,把函数编译成机器码运行,性能再提升10倍以上:
from numba import njit @njit def separate_string_numba(sentence: str): if not sentence: return "" res = [] for i in range(1, len(sentence), 2): c = sentence[i] res.append(chr(abs(ord(c) - 3))) return "".join(res)
第二步:替换apply为更高性能的执行方式
- 优先用
pd.Series.map代替apply,单进程下性能比apply高10%~20%:
df['re'] = df['col1'].map(separate_string_opt)
- 利用多核性能,用pandarallel库把任务分发到多个CPU核心执行,7核CPU可提升5~6倍速度:
from pandarallel import pandarallel # 初始化,设置使用核心数为7 pandarallel.initialize(nb_workers=7, progress_bar=True) # 用parallel_map代替map df['re'] = df['col1'].parallel_map(separate_string_opt)
- 如果数据量太大内存吃紧,可采用分块处理:读取数据时分批次读取,每次处理100万~200万行,处理完后写入存储再处理下一批,避免内存溢出。
第三步:极致性能优化(可选)
如果还需要更快的处理速度,可以把字符串列转成numpy数组,用C层面的向量化操作处理,或者用Dask框架并行处理大规模数据,性能可再提升数倍。
内容的提问来源于stack exchange,提问作者kinkajou
相关产品推荐
相关产品推荐

