You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何优化Python脚本以高效处理大型CSV文件?

如何优化Python脚本以高效处理大型CSV文件?

处理几个GB级的CSV文件确实是个头疼的问题,我之前也碰到过类似的场景——8GB内存的机器跑脚本经常崩溃,还得等几个小时。结合我的实践经验,给你分享几个既提速度又省内存的优化思路:

一、优化标准库csv模块的现有用法(零额外依赖)

如果不想引入新库,调整现有代码的细节就能带来明显提升:

  1. 调大文件缓冲区,减少磁盘IO次数
    默认的文件缓冲区很小,对于大文件来说会频繁读写磁盘,这是速度慢的核心原因之一。打开文件时指定buffering参数(比如10MB缓冲区),能大幅降低IO开销:
import csv

buffer = []
buffer_size = 10000  # 批量写入的行数

# 10MB缓冲区:1024*1024*10
with open('large_file.csv', 'r', buffering=1024*1024*10) as infile, \
     open('output_file.csv', 'w', newline='', buffering=1024*1024*10) as outfile:
    reader = csv.reader(infile)
    writer = csv.writer(outfile)
    
    # 先写入表头(如果原文件有表头的话)
    header = next(reader)
    writer.writerow(header)
    
    for row in reader:
        try:
            # 你的过滤/转换逻辑
            if int(row[2]) > 1000:
                buffer.append(row)
                # 攒够一批就批量写入
                if len(buffer) >= buffer_size:
                    writer.writerows(buffer)
                    buffer = []
        except (ValueError, IndexError):
            # 跳过格式错误的行
            continue
    # 写入剩余的行
    if buffer:
        writer.writerows(buffer)

关键改进:

  • 用writerows批量写入替代逐行writerow,减少系统调用次数
  • 调大缓冲区,降低磁盘IO的频率
  1. 避免不必要的类型转换
    如果你的转换逻辑里有大量类型转换(比如int(row[2])),可以提前确认列的类型,或者用更高效的转换方式,比如用fastnumbers库的fast_int函数(比内置int快),不过如果不想加依赖,尽量把转换逻辑简化。

二、用专用高性能库(推荐!)

对于大CSV处理,Python生态有几个专门优化的库,速度和内存效率远超标准库和pandas:

1. Polars(速度+内存双优,首选)

Polars是用Rust开发的DataFrame库,专门针对大型数据集优化,速度比pandas快5-10倍,内存占用只有pandas的1/3左右,而且支持懒加载(不会把整个文件读进内存)。

示例代码:

import polars as pl

# 懒加载文件,不占用内存
df = pl.scan_csv('large_file.csv')

# 应用过滤和转换(这里用列名,比索引更清晰)
# 假设第3列的列名是"value"
filtered_df = df.filter(pl.col("value") > 1000)

# 把结果写入CSV,延迟执行,全程高效
filtered_df.sink_csv('output_file.csv')

我之前处理5GB的CSV,用原csv脚本要3小时,用Polars只花了20分钟,内存占用一直稳定在几百MB。

2. Dask(适合超大型/分布式数据集)

如果你的文件大到单进程处理不过来(比如几十GB),Dask是个好选择——它可以自动分块处理,利用多核CPU,甚至可以扩展到集群。API和pandas几乎一致,学习成本低:

import dask.dataframe as dd

# 自动分块读取文件
df = dd.read_csv('large_file.csv')

# 过滤逻辑,和pandas语法完全一样
filtered_df = df[df['value'] > 1000]

# 写入结果,支持合并成单个文件
filtered_df.to_csv('output_file.csv', single_file=True, index=False)

Dask的优势是并行处理,适合转换逻辑复杂、CPU密集的场景。

3. 优化Pandas的用法(如果坚持用Pandas)

如果已经习惯Pandas,调整参数也能提升性能:

  • 指定列类型:避免Pandas自动推断类型(比如把int推断成object,既占内存又慢)
  • 调大chunksize:减少循环次数,比如从10000调到100000
  • 关闭低内存检查:low_memory=False

示例:

import pandas as pd

# 预先指定列的类型,比如第3列是int
dtypes = {'value': int}

# 调大chunksize到10万行
chunks = pd.read_csv(
    'large_file.csv',
    chunksize=100000,
    dtype=dtypes,
    low_memory=False
)

# 先写入表头
first_chunk = next(chunks)
first_chunk[first_chunk['value'] > 1000].to_csv('output_file.csv', index=False)

# 处理剩余chunk,追加写入
for chunk in chunks:
    filtered = chunk[chunk['value'] > 1000]
    filtered.to_csv('output_file.csv', mode='a', header=False, index=False)

三、其他通用优化技巧

  1. 用SSD代替机械硬盘:磁盘IO是大文件处理的常见瓶颈,SSD的读写速度是机械硬盘的10-100倍,换SSD后速度会有质的提升。
  2. 并行处理(CPU密集场景):如果你的转换逻辑是CPU密集型(比如复杂的数据清洗),可以用multiprocessing或concurrent.futures来并行处理chunk,但要注意避免多个进程同时写文件——最好每个进程处理完chunk写入临时文件,最后合并临时文件。
  3. 避免不必要的列:如果只需要处理部分列,在读取时指定usecols参数,比如csv.reader可以配合itertools.islice,Polars/Pandas可以指定usecols=["col1", "col2"],减少内存占用。

总结

  • 追求简单快速见效:用Polars,代码少、速度快、内存省
  • 超大型/分布式数据:用Dask
  • 不想加新依赖:优化标准库csv的缓冲区和批量写入
  • 习惯Pandas:调大chunksize+指定列类型

备注:内容来源于stack exchange,提问作者Lior Dahan

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.14 18:14:33