NumPy数组不是JSON序列化的

在创建NumPy数组后,并将其保存为Django上下文变量,我在加载网页时收到以下错误:

array([   0,  239,  479,  717,  952, 1192, 1432, 1667], dtype=int64) is not JSON serializable

这是什么意思?

435795 次浏览

我经常“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

为了“unjsonify"数组使用:

obj_text = codecs.open(file_path, 'r', encoding='utf-8').read()
b_new = json.loads(obj_text)
a_new = np.array(b_new)

此外,还有一些关于Python ~> Python列表vs.数组-何时使用?中的列表与数组的非常有趣的信息

可以注意到,一旦我在将数组保存到JSON文件中之前将其转换为列表,无论如何,在我现在的部署中,一旦我读取该JSON文件以供以后使用,我就可以继续以列表形式使用它(而不是将其转换回数组)。

在我看来,AND在屏幕上作为一个列表(逗号分隔)比数组(非逗号分隔)看起来更好。

使用上面的@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')

希望这能有所帮助!

下面是一个为我工作的实现,并删除了所有的nan(假设这些是简单的对象(list或dict)):

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

我有一个类似的问题,嵌套字典与一些numpy。ndarray在里面。

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

你可以使用熊猫:

import pandas as pd
pd.Series(your_array).to_json(orient='values')

默认情况下不支持这一点,但是您可以很容易地让它工作!如果你想要返回完全相同的数据,有几个东西你需要编码:

  • 数据本身,你可以通过obj.tolist()获得,就像@travelingbones提到的那样。有时这可能已经足够好了。
  • 数据类型。我觉得这在很多情况下很重要。
  • 维度(不一定是2D),如果你假设输入确实总是一个“矩形”网格,可以从上面得到。
  • 内存顺序(行或列为主)。这通常并不重要,但有时很重要(例如性能),所以为什么不保存所有内容呢?

此外,你的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))

存储为JSON一个numpy。Ndarray或任何嵌套列表组合。

class NumpyEncoder(json.JSONEncoder):
def default(self, obj):
if isinstance(obj, np.ndarray):
return obj.tolist()
return json.JSONEncoder.default(self, 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)

如果你在字典中嵌套了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)

感谢这家伙

这是一个不同的答案,但这可能有助于那些试图保存数据然后再次读取的人 有hickle比pickle更快更简单 我试图保存并在pickle dump中阅读它,但在阅读时有很多问题,浪费了一个小时,尽管我正在用自己的数据创建一个聊天机器人,但仍然没有找到解决方案。< / p >

vec_xvec_y是numpy数组:

data=[vec_x,vec_y]
hkl.dump( data, 'new_data_file.hkl' )

然后你只需读取它并执行以下操作:

data2 = hkl.load( 'new_data_file.hkl' )

你也可以使用default参数,例如:

def myconverter(o):
if isinstance(o, np.float32):
return float(o)


json.dump(data, default=myconverter)

使用json.dumps default kwarg:

Default应该是一个函数,用于无法序列化的对象. ...或引发TypeError

default函数中,检查对象是否来自模块numpy,如果是,则对ndarray使用ndarray.tolist,或对任何其他numpy特定类型使用.item

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)

可以做简单的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()

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)
但是幸运的是找到了解决抛出错误的提示 对象的序列化仅适用于以下转换 映射应该以以下方式进行 Object - dict Array - list 字符串-字符串 整数-整数

如果你向上滚动到第10行 forecast = loaded_model.predict(d)这行代码生成输出的位置 数组类型的数据类型,当你试图将数组转换为json格式是不可能的

最后,我发现解决方案只是通过转换获得的输出到类型列表由 下面的代码行

预测= loaded_model.predict(d)
Listtype = predict .tolist() 返回jsonify (listtype) < / p >

< p > Bhoom !最终得到了预期的产量, enter image description here < / p >

使用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)
如果其他人的代码(例如模块)正在执行json.dumps(),其他答案将不起作用。这种情况经常发生,例如,web服务器自动将其返回响应转换为JSON,这意味着我们不能总是更改json.dump()的参数。
这个答案解决了这个问题,并且基于一个(相对的)新的解决方案,适用于任何第三方类(不仅仅是numpy)。

TLDR

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]}'