NumPy 数组不可序列化为 JSON
- 2025-01-07 08:44:00
- admin 原创
- 163
问题描述:
创建 NumPy 数组并将其保存为 Django 上下文变量后,加载网页时收到以下错误:
array([ 0, 239, 479, 717, 952, 1192, 1432, 1667], dtype=int64) is not JSON serializable
这意味着什么?
解决方案 1:
我经常“jsonify”np.arrays。首先尝试在数组上使用“.tolist()”方法,如下所示:
import numpy as np
import codecs, json
a = np.arange(10).reshape(2,5) # a 2 by 5 array
b = a.tolist() # nested lists with same data, indices
file_path = "/path.json" ## your path variable
json.dump(b, codecs.open(file_path, 'w', encoding='utf-8'),
separators=(',', ':'),
sort_keys=True,
indent=4) ### this saves the array in .json format
为了“取消 JSON 化”数组,请使用:
obj_text = codecs.open(file_path, 'r', encoding='utf-8').read()
b_new = json.loads(obj_text)
a_new = np.array(b_new)
解决方案 2:
将 numpy.ndarray 或任何嵌套列表组合存储为 JSON。
class NumpyEncoder(json.JSONEncoder):
def default(self, obj):
if isinstance(obj, np.ndarray):
return obj.tolist()
return super().default(obj)
a = np.array([[1, 2, 3], [4, 5, 6]])
print(a.shape)
json_dump = json.dumps({'a': a, 'aa': [2, (2, 3, 4), a], 'bb': [2]},
cls=NumpyEncoder)
print(json_dump)
将会输出:
(2, 3)
{"a": [[1, 2, 3], [4, 5, 6]], "aa": [2, [2, 3, 4], [[1, 2, 3], [4, 5, 6]]], "bb": [2]}
要从 JSON 恢复:
json_load = json.loads(json_dump)
a_restored = np.asarray(json_load["a"])
print(a_restored)
print(a_restored.shape)
将会输出:
[[1 2 3]
[4 5 6]]
(2, 3)
解决方案 3:
如果字典中嵌套了 numpy 数组,我发现了最好的解决方案:
import json
import numpy as np
class NumpyEncoder(json.JSONEncoder):
""" Special json encoder for numpy types """
def default(self, obj):
if isinstance(obj, np.integer):
return int(obj)
elif isinstance(obj, np.floating):
return float(obj)
elif isinstance(obj, np.ndarray):
return obj.tolist()
return json.JSONEncoder.default(self, obj)
dumped = json.dumps(data, cls=NumpyEncoder)
with open(path, 'w') as f:
json.dump(dumped, f)
感谢这个家伙。
解决方案 4:
你可以使用Pandas:
import pandas as pd
pd.Series(your_array).to_json(orient='values')
解决方案 5:
使用json.dumps
default
关键字:
default 应该是一个针对无法序列化的对象调用的函数。......或者引发 TypeError
在default
函数中检查对象是否来自模块 numpy,如果是,则使用ndarray.tolist
它ndarray
或.item
用于任何其他 numpy 特定类型。
import numpy as np
def default(obj):
if type(obj).__module__ == np.__name__:
if isinstance(obj, np.ndarray):
return obj.tolist()
else:
return obj.item()
raise TypeError('Unknown type:', type(obj))
dumped = json.dumps(data, default=default)
解决方案 6:
默认情况下不支持此功能,但您可以轻松实现!如果您想要返回完全相同的数据,则需要对以下几项进行编码:
数据本身,您可以
obj.tolist()
像@travelingbones 提到的那样获取。有时这可能就足够了。数据类型。我觉得这在很多情况下都很重要。
维度(不一定是二维),如果您假设输入确实始终是一个“矩形”网格,则可以从上面得出。
内存顺序(行优先或列优先)。这通常并不重要,但有时却很重要(例如性能),那么为什么不保存所有内容呢?
此外,您的 numpy 数组可以作为数据结构的一部分,例如,您有一个包含一些矩阵的列表。为此,您可以使用自定义编码器,它基本上可以完成上述操作。
这应该足以实现解决方案。或者您可以使用json-tricks来实现这一点(并支持各种其他类型)(免责声明:我做到了)。
pip install json-tricks
然后
data = [
arange(0, 10, 1, dtype=int).reshape((2, 5)),
datetime(year=2017, month=1, day=19, hour=23, minute=00, second=00),
1 + 2j,
Decimal(42),
Fraction(1, 3),
MyTestCls(s='ub', dct={'7': 7}), # see later
set(range(7)),
]
# Encode with metadata to preserve types when decoding
print(dumps(data))
解决方案 7:
我在包含一些 numpy.ndarrays 的嵌套字典中遇到了类似的问题。
def jsonify(data):
json_data = dict()
for key, value in data.iteritems():
if isinstance(value, list): # for lists
value = [ jsonify(item) if isinstance(item, dict) else item for item in value ]
if isinstance(value, dict): # for nested lists
value = jsonify(value)
if isinstance(key, int): # if key is integer: > to string
key = str(key)
if type(value).__module__=='numpy': # if value is numpy.*: > to python list
value = value.tolist()
json_data[key] = value
return json_data
解决方案 8:
您还可以使用default
参数,例如:
def myconverter(o):
if isinstance(o, np.float32):
return float(o)
json.dump(data, default=myconverter)
解决方案 9:
如果其他人的代码(例如模块)正在执行 ,则其他答案将不起作用json.dumps()
。这种情况经常发生,例如,Web 服务器会自动将其返回响应转换为 JSON,这意味着我们不能总是更改 的参数json.dump()
。
这个答案解决了这个问题,并且基于一个适用于任何第三方类(不仅仅是numpy)的(相对)新的解决方案。
结论
pip install json_fix
import json_fix # import this anytime before the JSON.dumps gets called
import json
# create a converter
import numpy
json.fallback_table[numpy.ndarray] = lambda array: array.tolist()
# no additional arguments needed:
json.dumps(
dict(thing=10, nested_data=numpy.array((1,2,3)))
)
#>>> '{"thing": 10, "nested_data": [1, 2, 3]}'
解决方案 10:
此外,有关 Python 中的列表与数组的一些非常有趣的信息 ~> Python 列表与数组 - 何时使用?
值得注意的是,一旦我将数组转换为列表,然后将其保存在 JSON 文件中,无论如何,在我现在的部署中,一旦我读取该 JSON 文件以供稍后使用,我就可以继续以列表形式使用它(而不是将其转换回数组)。
实际上(在我看来)在屏幕上以列表(逗号分隔)而不是数组(非逗号分隔)的形式看起来更美观。
使用上面的@travelingbones 的 .tolist() 方法,我一直这样使用(捕获了我发现的一些错误):
保存词典
def writeDict(values, name):
writeName = DIR+name+'.json'
with open(writeName, "w") as outfile:
json.dump(values, outfile)
阅读字典
def readDict(name):
readName = DIR+name+'.json'
try:
with open(readName, "r") as infile:
dictValues = json.load(infile)
return(dictValues)
except IOError as e:
print(e)
return('None')
except ValueError as e:
print(e)
return('None')
希望这有帮助!
解决方案 11:
使用 NumpyEncoder 它将成功处理 json 转储。不会抛出 - NumPy 数组不是 JSON 可序列化的
import numpy as np
import json
from numpyencoder import NumpyEncoder
arr = array([ 0, 239, 479, 717, 952, 1192, 1432, 1667], dtype=int64)
json.dumps(arr,cls=NumpyEncoder)
解决方案 12:
这是一个对我有用的实现,它删除了所有的 nan(假设这些是简单对象(列表或字典)):
from numpy import isnan
def remove_nans(my_obj, val=None):
if isinstance(my_obj, list):
for i, item in enumerate(my_obj):
if isinstance(item, list) or isinstance(item, dict):
my_obj[i] = remove_nans(my_obj[i], val=val)
else:
try:
if isnan(item):
my_obj[i] = val
except Exception:
pass
elif isinstance(my_obj, dict):
for key, item in my_obj.iteritems():
if isinstance(item, list) or isinstance(item, dict):
my_obj[key] = remove_nans(my_obj[key], val=val)
else:
try:
if isnan(item):
my_obj[key] = val
except Exception:
pass
return my_obj
解决方案 13:
这是一个不同的答案,但这可能有助于帮助那些试图保存数据然后再次读取的人。
有比 pickle 更快、更简单的 hickle。
我尝试在 pickle dump 中保存和读取它,但在读取时出现了很多问题,浪费了一个小时,尽管我正在处理自己的数据来创建一个聊天机器人,但仍然没有找到解决方案。
vec_x
并且vec_y
是 numpy 数组:
data=[vec_x,vec_y]
hkl.dump( data, 'new_data_file.hkl' )
然后你只需阅读并执行操作:
data2 = hkl.load( 'new_data_file.hkl' )
解决方案 14:
可以执行简单的 for 循环并检查类型:
with open("jsondontdoit.json", 'w') as fp:
for key in bests.keys():
if type(bests[key]) == np.ndarray:
bests[key] = bests[key].tolist()
continue
for idx in bests[key]:
if type(bests[key][idx]) == np.ndarray:
bests[key][idx] = bests[key][idx].tolist()
json.dump(bests, fp)
fp.close()
解决方案 15:
TypeError: array([[0.46872085, 0.67374235, 1.0218339 , 0.13210179, 0.5440686 , 0.9140083 , 0.58720225, 0.2199381 ]], dtype=float32) 不是 JSON 可序列化的
当我尝试将数据列表传递给 model.predict() 时抛出了上述错误,而我期望得到 json 格式的响应。
> 1 json_file = open('model.json','r')
> 2 loaded_model_json = json_file.read()
> 3 json_file.close()
> 4 loaded_model = model_from_json(loaded_model_json)
> 5 #load weights into new model
> 6 loaded_model.load_weights("model.h5")
> 7 loaded_model.compile(optimizer='adam', loss='mean_squared_error')
> 8 X = [[874,12450,678,0.922500,0.113569]]
> 9 d = pd.DataFrame(X)
> 10 prediction = loaded_model.predict(d)
> 11 return jsonify(prediction)
但幸运的是找到了解决抛出错误的提示对象的序列化仅适用于以下转换映射应按以下方式进行对象 - 字典数组 - 列表字符串 - 字符串整数 - 整数
如果你向上滚动看到行号 10 prediction = loaded_model.predict(d),其中此行代码生成类型为 array datatype 的输出,当你尝试将 array 转换为 json 格式时,这是不可能的
最后我找到了解决方案,只需按照以下代码行将获得的输出转换为类型列表即可
预测 = loaded_model.predict(d)
listtype = prediction.tolist() 返回 jsonify(listtype)
Bhoom!终于得到了预期的输出,
解决方案 16:
我遇到了同样的问题,但略有不同,因为我的值来自 float32 类型,所以我将它们转换为简单的 float(值)。
扫码咨询,免费领取项目管理大礼包!