如何避免Python读取大CSV时内存占满至100%导致系统冻结?
解决大CSV文件读取内存耗尽的问题
兄弟,我太懂你这种崩溃的感受了——16GB的CSV直接塞进内存,连64GB RAM都扛不住,系统直接原地冻结,重启都得等半天对吧?其实问题出在pandas默认会把整个文件加载到内存,而CSV转成DataFrame后实际占用的内存往往是原文件的2-5倍(因为pandas会给列分配更“安全”的数据类型),16GB的文件撑爆64GB内存完全不意外。
下面给你几个实用的解决方案,按易上手程度排序:
1. 分块读取+逐步处理
这是最直接的改进方式,用pandas的chunksize参数把文件拆成小块,每次只加载一部分到内存,处理完就释放空间:
import pandas as pd from time import time filename = 'AKER_OB.csv' chunk_size = 10_000_000 # 每次读1000万行,可根据你的内存调整大小 timestamp_col = 'timestamp' # 替换成你实际的时间戳列名 start_ = time() # 存储每个排序后的块 sorted_chunks = [] # 分块读取并排序 for chunk in pd.read_csv(filename, chunksize=chunk_size, parse_dates=[timestamp_col]): # 对当前块按时间戳排序 sorted_chunk = chunk.sort_values(by=timestamp_col) sorted_chunks.append(sorted_chunk) # 合并所有块后再整体排序(如果合并后内存还够的话) merged_df = pd.concat(sorted_chunks) final_sorted_df = merged_df.sort_values(by=timestamp_col) # 保存结果 final_sorted_df.to_csv('AKER_OB_sorted.csv', index=False) end_ = time() print(f"处理完成,耗时{end_ - start_:.2f}秒")
如果合并后的DataFrame还是太大,你可以把每个排序后的块先存成临时CSV,再用归并排序的方式合并(或者直接用下面的Dask工具)。
2. 指定数据类型减少内存占用
很多时候内存浪费是因为pandas默认的类型太“冗余”,比如把字符串列设为object,整数设为int64。手动指定更紧凑的类型能大幅降低内存占用:
# 先读一小部分数据查看列类型 sample_df = pd.read_csv(filename, nrows=1000) print(sample_df.dtypes) # 自定义类型映射,根据你的实际列调整 dtype_spec = { 'id': 'int32', # 如果数值范围不大,用int32代替int64 'status': 'category', # 重复值多的字符串列用category类型,能省80%以上内存 'timestamp': 'datetime64[ns]' # 直接解析为datetime,比存字符串更高效还方便排序 } # 分块读取时应用类型 for chunk in pd.read_csv(filename, chunksize=chunk_size, dtype=dtype_spec, parse_dates=[timestamp_col]): # 排序逻辑同上...
3. 用Dask处理超大数据集
如果pandas的分块还是不够用,试试Dask——它是专门为超大数据集设计的并行计算库,用法和pandas几乎一致,但会自动在后台处理分块和内存管理:
import dask.dataframe as dd from time import time filename = 'AKER_OB.csv' timestamp_col = 'timestamp' start_ = time() # 读取CSV,Dask自动分块 ddf = dd.read_csv(filename, parse_dates=[timestamp_col]) # 按时间戳排序(Dask会自动处理外部排序,不用管内存) sorted_ddf = ddf.sort_values(by=timestamp_col) # 保存结果,默认生成多个分块文件,加single_file=True可生成单个文件 sorted_ddf.to_csv('AKER_OB_sorted.csv', index=False, single_file=True) end_ = time() print(f"处理完成,耗时{end_ - start_:.2f}秒")
4. 用命令行工具快速搞定
如果不想写代码,直接用Linux的sort命令——它天生支持大文件的外部排序,速度快还不占多少内存:
# 假设时间戳在第3列(从1开始计数),用逗号分隔列 sort -t ',' -k3,3 AKER_OB.csv > AKER_OB_sorted.csv
如果你的时间戳是字符串格式,可能需要加-V参数按版本号排序(比如处理带日期的字符串):
sort -t ',' -k3,3 -V AKER_OB.csv > AKER_OB_sorted.csv
内容的提问来源于stack exchange,提问作者Jeremie
相关产品推荐
相关产品推荐

