You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

如何在Python中高效读取大型CSV文件并避免内存不足问题

如何在Python中高效读取大型CSV文件并避免内存不足问题

嗨,我完全懂处理千万级行CSV时内存不够用的崩溃感——之前做用户行为分析时,我也跟你一样踩过这个坑!下面就针对你提到的几种方法详细拆解,再分享些实战中的最佳实践,帮你搞定大文件处理:


一、用Pandas的chunksize分块读取(平衡易用性和内存)

这个方法是我处理大CSV时最常用的,既保留了Pandas的便捷性,又不会一次性把文件塞进内存。核心思路是把文件拆成小“块”,逐块处理后释放内存,再处理下一块。

举个实际例子,比如你要过滤某列大于100的行,同时统计该列总和:

import pandas as pd

# 根据你的内存大小设置块大小,比如10万行(可以按需调整)
chunk_size = 100000
# 创建块迭代器,指定数据类型节省内存
chunk_iter = pd.read_csv('large_file.csv', chunksize=chunk_size, 
                         dtype={'value': 'float32', 'id': 'int32'})

# 初始化结果变量,或者准备输出文件
total_value = 0
output_path = 'filtered_data.csv'

# 先处理第一个块,写入表头
first_chunk = next(chunk_iter)
filtered_first = first_chunk[first_chunk['value'] > 100]
filtered_first.to_csv(output_path, index=False)
total_value += first_chunk['value'].sum()

# 循环处理剩余块
for chunk in chunk_iter:
    # 这里写你的业务逻辑:过滤、计算、聚合都可以
    filtered_chunk = chunk[chunk['value'] > 100]
    # 追加到输出文件,不要重复写表头
    filtered_chunk.to_csv(output_path, mode='a', header=False, index=False)
    # 累加统计值
    total_value += chunk['value'].sum()

print(f"列value的总和是:{total_value}")

注意事项

  • 不要把所有块都存在列表里(比如chunks = list(chunk_iter)),这样又会占满内存;
  • 尽量在块级别完成计算(比如累加、分组统计),避免把所有数据合并成一个大DataFrame;
  • 一定要指定dtype,默认的int64/float64会占用双倍内存,用int32/float32足够的话能省一半空间。

二、Dask DataFrame(大文件的Pandas平替)

Dask绝对是处理超大型数据集的好选择——它的API几乎和Pandas一模一样,不用改太多代码就能实现“大于内存”的数据处理。它会自动把数据拆成块,后台并行处理,最后按需把结果拉回内存。

示例代码:

import dask.dataframe as dd

# 读取CSV,Dask会自动分块(默认块大小是64MB左右)
ddf = dd.read_csv('large_file.csv', usecols=['id', 'category', 'value'],  # 只读需要的列
                  dtype={'value': 'float32'})

# 做和Pandas一样的操作:过滤、分组统计
filtered_ddf = ddf[ddf['value'] > 100]
# 分组求均值,注意这里只是定义计算逻辑,还没执行
group_mean = filtered_ddf.groupby('category')['value'].mean()

# 执行计算并获取结果(如果结果不大的话)
result = group_mean.compute()
print(result)

# 把过滤后的数据写入文件,支持生成单个文件或多个分块文件
filtered_ddf.to_csv('dask_filtered.csv', single_file=True, index=False)

适用场景

  • 当你的代码本来就是用Pandas写的,不想重构,只是数据太大装不下内存;
  • 需要并行处理来加快速度(Dask会利用多核CPU);
  • 如果最终计算结果还是很大,也可以继续用Dask的API处理,不用拉回内存。

三、原生csv模块(极致内存节省)

如果你的处理逻辑比较简单,而且对内存占用要求极致,原生的csv.readercsv.DictReader是最佳选择——它逐行读取文件,内存占用几乎可以忽略,缺点是需要自己处理数据类型、缺失值这些细节,速度也不如Pandas/Dask。

示例:

import csv

total_value = 0
# 用DictReader可以按列名访问行数据,比reader更直观
with open('large_file.csv', 'r', encoding='utf-8') as f:
    reader = csv.DictReader(f)
    for row in reader:
        # 手动转换数据类型(避免字符串占用冗余内存)
        value = float(row['value'])
        if value > 100:
            # 这里可以写入新文件,或者做简单计算
            total_value += value

print(f"列value的总和是:{total_value}")

适用场景

  • 内存极其有限(比如低配服务器);
  • 处理逻辑简单,不需要复杂的Pandas操作(比如只是过滤、计数、简单累加)。

额外优化技巧

  1. 只读取需要的列:不管用哪种方法,都用usecols参数指定要加载的列,避免加载无关数据;
  2. 处理缺失值:提前用na_values指定缺失值标识(比如pd.read_csv(..., na_values=['NA', ''])),避免Pandas把缺失值识别成其他类型;
  3. 转成更高效的文件格式:如果可以的话,把CSV转成Parquet或Feather——这些是列存储格式,压缩率高,读取速度快,内存占用只有CSV的几分之一,Pandas和Dask都支持读写;
  4. 并行加速:如果用原生csv模块,可以结合multiprocessing做并行处理(注意要把文件分成多个部分,避免多进程同时读同一个文件的冲突);
  5. 监控内存使用:用memory_profiler库监控代码的内存占用,找到内存瓶颈所在。

备注:内容来源于stack exchange,提问作者R. Marolahy

火山引擎 最新活动