使用Pandas读取大型CAN日志CSV文件时遇内存错误求助
解决Pandas读取大CSV内存不足问题的方案
问题根源
- 你之前的分块代码只是把迭代器直接转成DataFrame,本质还是一次性加载全量数据,没发挥分块作用
- Pandas默认把所有列存成
object类型,这种类型内存占用极高,348MiB的需求就是这么来的
方法1:指定数据类型压缩内存占用
CAN日志里大部分列是数值型,主动指定数据类型能大幅降低内存消耗。先采样小批量数据推断类型,再全量读取:
import pandas as pd import dtale # 先读1000行样本,推断各列合适的数据类型 sample_df = pd.read_csv(r'C:\Thesis\Log_Files\InputOutput\Input\Test_Log.csv', sep=';', nrows=1000) dtype_map = {} for col in sample_df.columns: # 优先转成int32(比int64省一半内存),不行再转float32,最后保留object try: sample_df[col].astype(int) dtype_map[col] = 'int32' except: try: sample_df[col].astype(float) dtype_map[col] = 'float32' except: dtype_map[col] = 'object' # 用推断的类型读取全量数据,还可以加usecols只加载需要分析的列 df = pd.read_csv(r'C:\Thesis\Log_Files\InputOutput\Input\Test_Log.csv', sep=';', dtype=dtype_map) # 若还是内存紧张,只加载目标列:df = pd.read_csv(..., usecols=['列1','列2'], dtype=dtype_map) dtale.show(df)
方法2:正确用分块做增量分析
调小分块尺寸,只加载需要的列,避免一次性处理全量数据:
import pandas as pd import dtale chunk_size = 50000 # 根据内存情况调整,比如改成20000 target_cols = ['需要分析的列名1', '需要分析的列名2'] # 只保留要分析的列 # 遍历分块逐个处理 for idx, chunk in enumerate(pd.read_csv(r'C:\Thesis\Log_Files\InputOutput\Input\Test_Log.csv', sep=';', chunksize=chunk_size, usecols=target_cols)): print(f"处理第{idx+1}块数据") # 这里可以加分析逻辑,比如统计、过滤 print(chunk.describe()) # 若要查看单个块的详情,再调用dtale # dtale.show(chunk)
方法3:用Dask处理超内存数据
Dask支持类似Pandas的API,能处理超出内存的数据集,不用一次性加载全量:
import dask.dataframe as dd from dask.diagnostics import ProgressBar # 用Dask读取CSV,自动分块 ddf = dd.read_csv(r'C:\Thesis\Log_Files\InputOutput\Input\Test_Log.csv', sep=';') # 执行分析操作,比如计算统计量,compute()才会实际运行 with ProgressBar(): stats = ddf.describe().compute() print(stats) # 若数据能放进内存,再转成Pandas DataFrame用dtale查看 # df = ddf.compute() # dtale.show(df)
额外优化小技巧
- 关闭Jupyter里其他没用的进程/标签页,释放内存
- 别直接用dtale加载全量数据,先通过Pandas做过滤、聚合,再用dtale看结果
- 把CSV转成Parquet格式(压缩率高、读取快):
# 能读取的话先转存 df.to_parquet('test_log.parquet') # 后续读取用Parquet,内存占用大幅降低 df = pd.read_parquet('test_log.parquet')
内容的提问来源于stack exchange,提问作者Pavan
相关产品推荐
相关产品推荐

