Python使用pd.merge合并大CSV报MemoryError内存错误问题求助
问题根因
触发527G内存报错和设备性能无关,核心是两个CSV的连接键isin存在大量重复值,pd.merge执行内连接时会对重复键做全量笛卡尔匹配,最终生成37亿行的无效中间结果,远超出64G内存承载上限。
分步落地方案
第一步:优先排查并清理重复键(90%的场景可直接解决问题)
金融场景下isin是证券类资产的唯一编码,正常单条资产记录对应唯一isin,出现天量匹配结果基本都是源文件存在重复数据导致的,先做这一步,不要上来就换工具。
直接复制运行以下代码,全程内存占用不超过1G,可快速定位重复问题:
import pandas as pd # 仅读取两个文件的isin列,不加载全量数据 isin_col1 = pd.read_csv("替换为你的第一个CSV文件完整路径.csv", usecols=['isin']) isin_col2 = pd.read_csv("替换为你的第二个CSV文件完整路径.csv", usecols=['isin']) # 打印重复情况统计 print(f"表1 isin总记录数:{len(isin_col1)}") print(f"表1 去重后isin数量:{isin_col1['isin'].nunique()}") print(f"表2 isin总记录数:{len(isin_col2)}") print(f"表2 去重后isin数量:{isin_col2['isin'].nunique()}")
如果输出结果里去重后的isin数量远小于总记录数,说明存在重复行,先按业务规则去重再合并,参考代码如下(可直接修改列名后运行):
# !!!重要:只读取你实际需要用到的列,不要加载无关字段,至少能省60%内存 # 把下面列表里的内容替换成你要保留的列名即可 need_cols1 = ['isin', '需要保留的表1字段1', '需要保留的表1字段2', '需要保留的表1字段3'] need_cols2 = ['isin', '需要关联带出的表2字段1', '需要关联带出的表2字段2'] # 加载需要的字段,同时指定isin为字符串类型,避免匹配错误 data1 = pd.read_csv("替换为你的第一个CSV文件完整路径.csv", usecols=need_cols1, dtype={'isin': 'string'}) data2 = pd.read_csv("替换为你的第二个CSV文件完整路径.csv", usecols=need_cols2, dtype={'isin': 'string'}) # 去重:如果同个isin存在多条完全重复的行,直接去重;如果是同个isin对应多时间点记录,按业务规则筛选 # 示例:同isin保留最后一条记录,可根据需求修改keep参数 data1 = data1.drop_duplicates(subset='isin', keep='last') data2 = data2.drop_duplicates(subset='isin', keep='last') # 执行合并,此时数据量会回归正常水平,不会触发内存错误 final_data = pd.merge(data1, data2, on='isin', how='inner') # 导出结果,index=False表示不导出行号 final_data.to_csv("合并完成结果.csv", index=False)
第二步:业务确需保留isin下多条记录的低内存合并方案
如果你要做的是类似「isin对应的多日行情数据+isin对应的静态基本面数据」这类关联,单isin确实对应多条记录,不需要去重,就用Dask框架做内存调度,语法和pandas几乎一致,不需要改原有逻辑,64G内存完全可以支撑。
操作步骤:
- 安装依赖:打开终端/命令提示符,执行以下命令:
pip install dask[dataframe] - 复制运行以下代码,替换文件路径即可:
import dask.dataframe as dd import dask # 限制程序最大用50G内存,预留10G给系统运行,避免死机 dask.config.set({"memory_limit": "50GB"}) # 加载两个CSV文件,指定isin为字符串类型 ddf1 = dd.read_csv("替换为你的第一个CSV文件完整路径.csv", dtype={'isin': 'string'}) ddf2 = dd.read_csv("替换为你的第二个CSV文件完整路径.csv", dtype={'isin': 'string'}) # 内连接,语法和pandas完全一致 final_ddf = dd.merge(ddf1, ddf2, on='isin', how='inner') # 导出为单个CSV文件,自动做分块内存调度,不会爆内存 final_ddf.to_csv("合并完成结果.csv", index=False, single_file=True)
避坑提醒
- 不要用Excel打开几百M以上的CSV文件,会直接卡死,用VS Code或者Notepad++查看前几行确认列名即可。
- 读文件时必须指定
isin为字符串类型,否则框架会自动把编码识别为数字,不仅容易出现匹配错误,还会额外占用内存。 - 无关字段一律不要读入内存,比如冗余的备注列、临时统计列,加载的列越少,合并速度越快,内存占用越低。
内容的提问来源于stack exchange,提问作者dabrows
相关产品推荐
相关产品推荐

