如何不使用Pandas实现JSON对象的Explode展开并避免内存溢出?
不依赖Pandas实现JSON结构转换并避免内存溢出的方案
需求说明
输入JSON结构:
{"data": {"geography": [{"id": "1","state": "USA","properties": [{"code": "CMD-01","value": "34"},{"code": "CMD-02","value": "24"}]},{"id": "2","state": "Canada","properties": [{"code": "CMD-04","value": "50"},{"code": "CMD-05","value": "60"}]}]}}
需要转换为以下扁平结构,且不能使用Pandas的explode/flatten/normalize等函数,同时避免内存溢出:
{"id": "1", "state": "USA", "code": "CMD-01", "value": "34"}, {"id": "1", "state": "USA", "code": "CMD-02", "value": "24"}, {"id": "2", "state": "Canada", "code": "CMD-04", "value": "50"}, {"id": "2", "state": "Canada", "code": "CMD-05", "value": "60"}
解决方案:基于原生Python的迭代/流式处理
核心思路是避免一次性加载所有数据到内存,通过迭代生成结果,仅在需要时创建单个对象,从根源上防止OOM。
场景1:JSON已加载到内存(小/中等规模数据)
使用Python生成器(yield)惰性生成结果,内存占用始终保持在单个元素级别:
import json # 输入JSON字符串(或已解析的Python字典) input_json = json.loads('''{"data": {"geography": [{"id": "1","state": "USA","properties": [{"code": "CMD-01","value": "34"},{"code": "CMD-02","value": "24"}]},{"id": "2","state": "Canada","properties": [{"code": "CMD-04","value": "50"},{"code": "CMD-05","value": "60"}]}]}}''') def flatten_geo_data(data): # 遍历每个地理条目 for geo_entry in data["data"]["geography"]: base_info = {"id": geo_entry["id"], "state": geo_entry["state"]} # 遍历当前条目的所有属性,合并后生成新对象 for prop in geo_entry["properties"]: yield {**base_info, **prop} # 迭代输出结果(或逐行写入文件) for item in flatten_geo_data(input_json): print(json.dumps(item)) # 写入文件示例: # with open("output.json", "a") as f: # f.write(json.dumps(item) + ",\n")
场景2:超大JSON文件(无法一次性加载到内存)
使用轻量流式JSON解析库ijson,逐元素解析输入文件,完全避免加载整个文件到内存:
- 先安装依赖:
pip install ijson - 实现代码:
import ijson import json def stream_flatten_large_file(input_path): with open(input_path, "r") as f: # 流式遍历geography数组的每个元素 for geo_entry in ijson.items(f, "data.geography.item"): base_info = {"id": geo_entry["id"], "state": geo_entry["state"]} for prop in geo_entry["properties"]: yield {**base_info, **prop} # 处理大文件并逐行写入输出 for idx, item in enumerate(stream_flatten_large_file("large_input.json")): with open("output.json", "a") as out_f: # 处理最后一个元素的 trailing comma(可选,多数JSON解析器可兼容未处理的情况) suffix = ",\n" out_f.write(json.dumps(item) + suffix)
关键优势
- 生成器/流式处理仅在迭代时生成单个结果对象,内存占用极低
- 无需依赖Pandas等重型库,代码轻量易维护
- 适配从小数据到超大文件的各种场景
内容的提问来源于stack exchange,提问作者Pira123
相关产品推荐
相关产品推荐

