NumPy数组不是JSON可序列化的

时间:2014-10-30 06:23:48

标签: python json django numpy

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

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

这是什么意思?

14 个答案:

答案 0 :(得分:201)

我经常" 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)

答案 1 :(得分:120)

将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)

答案 2 :(得分:32)

您可以使用Pandas

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

答案 3 :(得分:23)

如果您在字典中嵌套了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.int_, np.intc, np.intp, np.int8,
            np.int16, np.int32, np.int64, np.uint8,
            np.uint16, np.uint32, np.uint64)):
            return int(obj)
        elif isinstance(obj, (np.float_, np.float16, np.float32, 
            np.float64)):
            return float(obj)
        elif isinstance(obj,(np.ndarray,)): #### This is the fix
            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)

感谢this guy

答案 4 :(得分:8)

许多其他的numpy编码器似乎过于冗长。

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

使用json.dumps default kwarg:

  

默认值应该是一个针对无法序列化的对象调用的函数。

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)

答案 5 :(得分:4)

默认情况下不支持此功能,但您可以轻松使用它!如果您想要完全相同的数据,有几件事情需要编码:

  • 数据本身,您可以使用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))

答案 6 :(得分:3)

我在嵌套字典中遇到了类似的问题,其中包含一些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

答案 7 :(得分:3)

您还可以使用default参数,例如:

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

json.dump(data, default=myconverter)

答案 8 :(得分:2)

使用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)

答案 9 :(得分:1)

此外,关于列表与Python中的数组的一些非常有趣的信息〜> Python List vs. Array - when to use?

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

实际上在屏幕上看起来更好(在我看来)作为列表(逗号分隔)与数组(非逗号分隔)这种方式。

使用上面的@transbones的.tolist()方法,我一直在使用(捕捉到我发现的一些错误):

保存字典

protected void onDraw(Canvas c) {
    c.rotate(-90);
    c.translate(-getHeight(), 0);
    drawThumb(c); //redrawing thumb

    super.onDraw(c);
}

void drawThumb(Canvas canvas) {
    Drawable thumb = getThumb();
    if (thumb != null) {
        Rect thumbBounds = thumb.getBounds();
        canvas.save();
        canvas.rotate(90, thumbBounds.exactCenterX(), thumbBounds.exactCenterY());
        thumb.draw(canvas);
        canvas.restore();
    }
}

阅读字典

def writeDict(values, name):
    writeName = DIR+name+'.json'
    with open(writeName, "w") as outfile:
        json.dump(values, outfile)

希望这有帮助!

答案 10 :(得分:1)

这是一个适合我并且删除了所有nans的实现(假设这些是简单的对象(列表或字典)):

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

答案 11 :(得分:1)

这是一个不同的答案,但这可能有助于帮助试图保存数据然后再次读取的人。
比起泡菜更快更容易。
我试图保存它并在pickle dump中阅读,但是阅读时有很多问题,浪费了一个小时,尽管我正在处理自己的数据来创建聊天机器人,但仍然找不到解决方案。

vec_xvec_y是numpy数组:

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

然后您只需阅读并执行操作:

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

答案 12 :(得分:1)

可以使用检查类型简化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()

答案 13 :(得分:1)

TypeError:array([[[0.46872085,0.67374235,1.0218339,0.13210179,0.5440686,0.9140083,0.58720225,0.2199381]],dtype = float32)不是JSON可序列化的

当我期望以json格式响应时,尝试将数据列表传递给model.predict()时,抛出了上述错误。

a = []
b = []

while len(a) < 11:
    a.append(int(input("enter a number:")))
    if len(a) == 10:
        break

    print('Original keyed in numbers are:',a)

for index in range(len(a)):
    if a[index] > 5:
        continue
    b.append(a[index])

print('These are numbers you entered that are less than or equal to 5:',b)

但幸运的是找到了解决抛出错误的提示   对象的序列化仅适用于以下转换   映射应采用以下方式   对象-dict   数组列表   字符串-字符串   整数-整数

如果向上滚动以查看行号10   预测= loading_model.predict(d)此行代码在其中生成输出的位置   类型为数组数据类型,当您尝试将数组转换为json格式时

最后我找到了解决方案,方法是将获得的输出转换为类型列表   以下代码行

  

预测= loading_model.predict(d)
  列表类型= projection.tolist()   返回jsonify(listtype)

嘘!终于得到了预期的输出,   enter image description here