如何高效将多份结构不一致的JSON文件转换为单个Pandas DataFrame?
处理多结构JSON文件生成Pandas DataFrame的优化方案
一、解决AttributeError: 'str' object has no attribute 'read'报错
这个错误本质是文件路径与文件对象的处理混淆:比如你给json.load()传了文件路径字符串(而非打开的文件对象),或者给pd.read_json()的参数类型不符合要求。
以下是正确的生成器处理逻辑,逐文件加载并转换为小DataFrame后yield:
import pandas as pd import json from pathlib import Path def process_single_json(path): with open(path, 'r') as f: data = json.load(f) # 提取基础字段、受害者数据,遍历攻击者生成扁平行 base_fields = {k: v for k, v in data.items() if k not in ['attackers', 'victim']} victim_flat = {f'victim_{k}': v for k, v in data['victim'].items()} rows = [] for attacker in data['attackers']: attacker_flat = {f'attacker_{k}': v for k, v in attacker.items()} rows.append({**base_fields, **attacker_flat, **victim_flat}) return pd.DataFrame(rows) def json_file_generator(file_paths): for path in file_paths: yield process_single_json(path) # 调用示例 file_list = list(Path('./your_json_dir').glob('*.json')) final_df = pd.concat(json_file_generator(file_list), ignore_index=True)
二、性能优化方案对比
1. 生成器+逐文件处理(推荐中小数据量)
- 优势:无需一次性加载所有文件到内存,
pd.concat直接接收生成器,内存占用仅为单文件处理后的大小,避免二次复制所有数据。 - 关键:不要先把所有小DataFrame存入列表再concat,直接将生成器传入
pd.concat,减少内存开销。
2. JSONL中间文件方案(适合超大规模数据)
如果数据量远超内存,先将所有JSON转换为JSONL格式(每行对应一个攻击者+受害者的扁平数据),再分块读取:
import json from pathlib import Path def convert_to_jsonl(input_dir, output_path): with open(output_path, 'w') as out_f: for path in Path(input_dir).glob('*.json'): with open(path, 'r') as in_f: data = json.load(in_f) base_fields = {k: v for k, v in data.items() if k not in ['attackers', 'victim']} victim_flat = {f'victim_{k}': v for k, v in data['victim'].items()} for attacker in data['attackers']: attacker_flat = {f'attacker_{k}': v for k, v in attacker.items()} flat_row = {**base_fields, **attacker_flat, **victim_flat} out_f.write(json.dumps(flat_row) + '\n') # 转换为JSONL convert_to_jsonl('./your_json_dir', './output.jsonl') # 分块读取JSONL chunk_df = pd.read_json('./output.jsonl', lines=True, chunksize=10000) final_df = pd.concat(chunk_df, ignore_index=True)
- 优势:支持分块读取,彻底规避内存不足问题;后续读取无需再处理拆分逻辑。
- 劣势:多一次磁盘IO操作,适合数据量极大的场景。
3. 替换apply(pd.Series)提升速度
原方案中apply(pd.Series)是性能瓶颈,用直接构造扁平字典的方式替代,能大幅提升处理速度(尤其是攻击者数量较多时),示例见第一部分的process_single_json函数。
三、总结
- 中小数据量:优先用「生成器+扁平字典构造」方案,兼顾内存效率与处理速度。
- 超大规模数据:先转JSONL再分块读取,彻底解决内存限制问题。
- 生成器报错核心:确保文件读取时用
open()获取文件对象,而非直接传路径字符串给解析函数。
内容的提问来源于stack exchange,提问作者Niko Lass
相关产品推荐
相关产品推荐

