如何加速将大量列表转换为Pandas DataFrame的低效代码?
哇,这个逐行append的操作绝对是pandas里的性能杀手!处理大文件时跑几天太正常了,我给你几个靠谱的优化方案,能把速度提上去好几个数量级:
核心优化思路:避免频繁修改DataFrame
pandas的DataFrame.append()每次都会创建一个新的DataFrame对象,相当于把整个数据集复制一遍——数据量越大,这个开销就指数级增长。我们要做的就是先把所有结果收集到轻量的容器里,最后一次性生成DataFrame。
1. 最直接的优化:用列表收集结果再批量转换
这是提升最明显、实现最简单的方案,把所有my_fun的结果先存在普通Python列表里,最后统一转成DataFrame:
# 初始化空列表存结果 results = [] # 直接遍历XYZ的行(比用索引更简洁高效) for row in XYZ: # 调用函数并把结果加入列表 row_result = my_fun(row) results.append(row_result) # 最后一次性生成DataFrame,一步到位! pandas_frame = pd.DataFrame(results)
如果原代码里的transpose()是因为my_fun返回的是列格式数据,那可以在收集时调整:比如把row_result转成字典或者行格式的序列,或者最后生成DF后统一转置,都比逐行转高效。
2. 用pandas的apply简化代码(适合XYZ本身是DataFrame的情况)
如果XYZ本身就是pandas DataFrame,直接用apply按行处理,代码更简洁,速度也比逐行append快:
# axis=1表示按行处理,把my_fun的结果转成Series pandas_frame = XYZ.apply(lambda row: pd.Series(my_fun(row)), axis=1)
不过这个方法的性能略逊于列表收集,胜在代码简洁。
3. 并行处理:榨干CPU多核性能
如果my_fun是CPU密集型任务,且每行处理完全独立,那可以用多进程/多线程并行处理,直接把时间压缩到几分之一:
from concurrent.futures import ProcessPoolExecutor # 把XYZ转成可迭代的行对象(比如如果是DataFrame就转成字典列表) rows_iter = XYZ.to_dict('records') if isinstance(XYZ, pd.DataFrame) else XYZ # 进程池并行处理,max_workers设为你的CPU核心数 with ProcessPoolExecutor(max_workers=4) as executor: results = list(executor.map(my_fun, rows_iter)) pandas_frame = pd.DataFrame(results)
如果是IO密集型任务(比如my_fun里有文件读写),换成ThreadPoolExecutor会更合适。
4. 从根源优化:重构my_fun函数
很多时候最大的瓶颈不在外部循环,而是my_fun内部的低效实现:
- 把函数里的Python循环改成列表推导式或生成器表达式
- 用numpy矢量化操作替代逐元素计算
- 尽量避免在
my_fun里频繁创建小DataFrame/Series
举个例子:如果原my_fun是这样的低效写法:
def my_fun(x): res = [] for item in x: res.append(item * 2 + 1) return res
改成numpy矢量化后速度会快10倍以上:
import numpy as np def my_fun(x): return (np.array(x) * 2 + 1).tolist()
优先级建议
- 先优化
my_fun本身(收益最大) - 用列表收集结果再批量转DF(性价比最高)
- 最后考虑并行处理(适合超大数据量或CPU密集场景)
内容的提问来源于stack exchange,提问作者Mysterious
相关产品推荐
相关产品推荐

