如何存储包含标量与ndarray的多层嵌套字典集合?
解决ndarray无法JSON序列化的几种实用方案
1. 把ndarray转成列表再存JSON
JSON只认Python原生类型,所以把所有ndarray转成普通列表就能正常序列化。可以写个递归函数自动遍历整个数据结构转换:
import json import numpy as np def ndarray_to_list(obj): if isinstance(obj, dict): return {k: ndarray_to_list(v) for k, v in obj.items()} elif isinstance(obj, list): return [ndarray_to_list(item) for item in obj] elif isinstance(obj, np.ndarray): return obj.tolist() else: return obj # 处理你的数据集合 processed_data = ndarray_to_list(your_list) # 写入JSON文件 with open('data.json', 'w') as f: json.dump(processed_data, f)
读取时再把需要的列表转回ndarray:
def list_to_ndarray(obj): if isinstance(obj, dict): return {k: list_to_ndarray(v) for k, v in obj.items()} elif isinstance(obj, list): try: return np.array(obj) except: return [list_to_ndarray(item) for item in obj] else: return obj with open('data.json', 'r') as f: loaded_data = json.load(f) restored_data = list_to_ndarray(loaded_data)
优点是JSON文件可读、跨语言通用;缺点是大数组转列表会占更多内存,读写速度慢。
2. 自定义JSON编码器
继承json.JSONEncoder专门处理ndarray,还能保留数组的dtype信息:
import json import numpy as np class NumpyEncoder(json.JSONEncoder): def default(self, obj): if isinstance(obj, np.ndarray): return {'__ndarray__': obj.tolist(), 'dtype': str(obj.dtype)} return super().default(obj) # 保存数据 with open('data.json', 'w') as f: json.dump(your_list, f, cls=NumpyEncoder) # 读取时解码 def decode_ndarray(obj): if '__ndarray__' in obj: return np.array(obj['__ndarray__'], dtype=obj['dtype']) elif isinstance(obj, dict): return {k: decode_ndarray(v) for k, v in obj.items()} elif isinstance(obj, list): return [decode_ndarray(item) for item in obj] else: return obj with open('data.json', 'r') as f: loaded_data = json.load(f, object_hook=decode_ndarray)
这种方式比单纯转列表更严谨,适合需要精确恢复数据的场景。
3. 用Pickle直接序列化(Python专属)
如果只在Python环境里用,Pickle是最省事的,它支持几乎所有Python对象的序列化,包括ndarray:
import pickle # 保存 with open('data.pkl', 'wb') as f: pickle.dump(your_list, f) # 读取 with open('data.pkl', 'rb') as f: loaded_data = pickle.load(f)
优点是代码简单、读写速度快,能完整保留所有数据结构;缺点是文件不可读,只能在Python中解析,版本兼容性可能有问题。
4. 用HDF5存大型数组
如果你的ndarray数据量很大,HDF5是更专业的选择,支持高效分块存储和随机访问:
import h5py # 保存 with h5py.File('data.h5', 'w') as f: def save_dict_to_hdf5(group, data): for k, v in data.items(): if isinstance(v, dict): sub_group = group.create_group(k) save_dict_to_hdf5(sub_group, v) elif isinstance(v, np.ndarray): group.create_dataset(k, data=v) else: group.attrs[k] = v for i, d in enumerate(your_list): list_group = f.create_group(f'dict{i+1}') save_dict_to_hdf5(list_group, d) # 读取 def load_dict_from_hdf5(group): result = {} for k, v in group.items(): if isinstance(v, h5py.Group): result[k] = load_dict_from_hdf5(v) elif isinstance(v, h5py.Dataset): result[k] = v[()] for k, v in group.attrs.items(): result[k] = v return result loaded_list = [] with h5py.File('data.h5', 'r') as f: for key in f.keys(): loaded_list.append(load_dict_from_hdf5(f[key]))
优点是适合超大型数组,支持压缩、分块,读写效率高;缺点是需要熟悉h5py的使用,文件结构相对复杂。
内容的提问来源于stack exchange,提问作者gintoki_
相关产品推荐
相关产品推荐

