You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何存储包含标量与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_

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.30 15:15:38