将大型Python字典转换为DataFrame时出现内存不足错误的解决方案咨询
解决大字典转DataFrame的内存不足问题
你的思路完全正确——不需要把整个字典、DataFrame都放在内存里,我们可以直接逐行处理数据并写入CSV,让内存中始终只保留当前正在处理的那一项数据,从根源上避免OOM问题。
核心优化思路
原来的代码会同时在内存中存储三个大对象:sents原始字典、sentences_dict转换后的字典、sentences_dfDataFrame,这三重内存占用是导致OOM的主要原因。我们可以砍掉后两个中间对象,直接遍历sents并实时写入CSV。
具体实现方案
下面是修改后的代码,用Python内置的csv模块(比pandas更轻量)来逐行写入数据,全程只保留当前处理的单条语句数据:
import csv # 先定义CSV表头:固定列 + 最多17个动词的对应字段(因为你过滤了num_tags < 18) header = ["Sentence", "num_verbs"] for j in range(1, 18): # 对应verbs_1到verbs_17 header.extend([ f"verbs_{j}", f"verbs_lemmas_{j}", f"verbs_pos_{j}", f"verbs_tags_{j}" ]) sents = extract(araneum) # 如果sents本身占用内存过大,可以遍历键列表并处理后删除原字典中的项,释放内存 sent_keys = list(sents.keys()) with open(output, "w", newline="") as res_csv: writer = csv.DictWriter(res_csv, fieldnames=header, delimiter=",") writer.writeheader() # 写入表头 for sent in sent_keys: features = sents.pop(sent) # 从原字典删除,释放内存 num_tags = len(features[0]) if num_tags < 18: # 构造当前行的数据 row_data = { "Sentence": sent, "num_verbs": num_tags } # 填充每个动词的特征字段 for j, (verb, pos, tag, lemma) in enumerate(features): idx = j + 1 row_data[f"verbs_{idx}"] = verb row_data[f"verbs_lemmas_{idx}"] = lemma row_data[f"verbs_pos_{idx}"] = pos row_data[f"verbs_tags_{idx}"] = tag # 写入当前行 writer.writerow(row_data)
为什么这个方案有效?
- 无中间大对象:不再生成
sentences_dict和sentences_df,避免了重复占用内存。 - 实时释放内存:通过
sents.pop(sent)处理完一条语句后,就从原始字典中删除它,让Python的垃圾回收机制及时释放这部分内存。 - 轻量写入工具:用内置
csv模块代替pandas的DataFrame写入,内存开销更低。
关于Pickle序列化的补充
如果确实需要先把sents序列化到磁盘再处理,你可以用pickle分块写入/读取,但其实上面的方案已经更高效了。如果一定要用pickle,也可以在序列化时就分块写入,读取时逐块加载处理,但步骤会更繁琐——相比之下,直接遍历sents并实时处理是最优解。
内容的提问来源于stack exchange,提问作者Irene Testini
相关产品推荐
相关产品推荐

