Python 3.6:加速Pandas DataFrame中的正则表达式替换
问题描述
我现在需要读取100万行共31个字段的SQL数据,替换其中的控制字符后导出为TSV文件,但当前代码的运行速度很慢,主要是
replace操作拖慢了整体效率,处理完需要16分钟。我的代码如下:d = {} x = map(chr, list(range(0,9)) + list(range(11,13)) + list(range(14,32)) + list(range(127,160))) for item in list(x): d.update({item:' '}) with open("out_cleaned.csv", "w", encoding='utf-8') as fh: chunks = pd.read_sql_query(SQLCommand, connection, chunksize=10000) c = next(chunks) c.replace(d, regex=True, inplace=True) c.to_csv(fh, index=False, header=False, sep='\t', chunksize=10000) for chunk in chunks: chunk.replace(d, regex=True, inplace=True) chunk.to_csv(fh, index=False, header=False, sep='\t', chunksize=10000)想请教有没有更高效的实现思路或优化方法来提升运行速度?
优化方案
1. 用str.translate替代正则replace——最核心的提速点
正则替换在处理大量单字符替换时效率极低,因为它需要逐行逐列进行正则匹配。而Python内置的str.translate是专门为单字符映射替换设计的,它会一次性完成所有目标字符的替换,速度比正则快好几个数量级。
你可以先把字符映射转换成str.maketrans要求的格式,然后只对字符串类型的列进行处理(数值列不存在控制字符,完全不需要浪费时间):
# 更简洁地构建控制字符列表和映射表 control_char_codes = list(range(0,9)) + list(range(11,13)) + list(range(14,32)) + list(range(127,160)) trans_table = str.maketrans({chr(c): ' ' for c in control_char_codes}) with open("out_cleaned.csv", "w", encoding='utf-8') as fh: chunks = pd.read_sql_query(SQLCommand, connection, chunksize=10000) str_cols = None # 缓存字符串类型列,避免重复检测 for chunk in chunks: if str_cols is None: # 仅筛选字符串类型的列(包括object和string dtype) str_cols = chunk.select_dtypes(include=['object', 'string']).columns.tolist() # 对每个字符串列应用translate替换 chunk[str_cols] = chunk[str_cols].apply(lambda col: col.str.translate(trans_table)) # 写出到文件 chunk.to_csv(fh, index=False, header=False, sep='\t', chunksize=10000)
2. 调整chunksize,减少循环与IO开销
当前设置的chunksize=10000偏小,导致循环次数过多,IO操作频繁。你可以尝试调大到50000或100000(具体数值根据你的机器内存调整,确保单chunk不会占用过多内存),这样能大幅减少循环次数和IO的次数,进一步提升整体速度。
3. 避免inplace=True的隐性开销
虽然inplace=True看似节省内存,但它可能会触发Pandas内部的额外操作,而且代码可读性较差。直接对列进行重新赋值(如上面代码中的chunk[str_cols] = ...)不仅更清晰,在多数情况下效率也更高。
4. 超大数据量场景:尝试Dask并行处理
如果未来数据量继续增长,或者你的机器内存有限,可以考虑使用Dask替代Pandas。Dask能自动将数据拆分成多个任务并行处理,对于这种批量清洗导出的场景,能带来显著的速度提升。不过这需要额外安装Dask库,适合更大规模的数据处理需求。
效果预估
使用str.translate替换正则replace后,处理速度通常能提升10-20倍,百万行31列的数据处理时间应该能压缩到1分钟以内(具体取决于你的硬件配置)。
内容的提问来源于stack exchange,提问作者HuFlungPu

