【问题标题】:NumPy array is not JSON serializableNumPy 数组不是 JSON 可序列化的
【发布时间】:2014-12-26 02:27:34
【问题描述】:

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

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

这是什么意思?

【问题讨论】:

  • 这意味着某处,某事试图使用json 模块转储一个numpy 数组。但是numpy.ndarray 不是json 知道如何处理的类型。您要么需要编写自己的序列化程序,要么(更简单地)将 list(your_array) 传递给正在编写 json 的任何内容。
  • 注意 list(your_array) 并不总是有效,因为它返回 numpy 整数,而不是本机整数。请改用your_array.to_list()
  • 关于@ashishsingal 评论的注释,应该是your_array.tolist(),而不是to_list()。

标签: python json django numpy


【解决方案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

为了“unjsonify”数组使用:

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

【讨论】:

  • 为什么只能存储为列表列表?
  • 我不知道,但我希望 np.array 类型具有不适合 json 的元数据(例如,它们指定每个条目的数据类型,如 float)
  • 我试过你的方法,但程序似乎卡在tolist()
  • @frankliuao 我发现原因是tolist()在数据量很大的情况下会占用大量时间。
  • @NikhilPrabhu JSON 是 Javascript 对象表示法,因此只能表示 javascript 语言的基本构造:对象(类似于 python dicts)、数组(类似于 python 列表)、数字、布尔值、字符串, 和空值(类似于python Nones)。 Numpy 数组不是这些东西,因此不能序列化为 JSON。有些可以转换为类似 JSO 的形式(列表列表),这就是这个答案的作用。
【解决方案2】:

将 numpy.ndarray 或任何嵌套列表组合存储为 JSON。

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)

【讨论】:

  • 这应该是更高层次的,它是通用且适当抽象的方法。谢谢!
  • 有没有一种简单的方法可以从列表中取回 ndarray ?
  • @DarksteelPenguin 你在找numpy.asarray()吗?
  • 这个答案很棒,可以很容易地扩展到将 numpy float32 和 np.float64 值序列化为 json:if isinstance(obj, np.float32) or isinstance(obj, np.float64): return float(obj)
  • 此解决方案避免您手动将每个 numpy 数组强制转换为列表。
【解决方案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)

感谢this guy

【讨论】:

  • 感谢您的帮助!我将属性写入 json 文件,但现在无法读取 Logistic 回归的参数。这个保存的 json 文件是否有“解码器”?
  • 当然,要读取json 后面的内容,您可以使用:with open(path, 'r') as f: data = json.load(f),它会返回包含您数据的字典。
  • 那是为了读取json文件然后反序列化它的输出你可以使用这个:data = json.loads(data)
  • 我必须添加它来处理字节数据类型。假设所有字节都是 utf-8 字符串。 elif isinstance(obj, (bytes,)): return obj.decode("utf-8")
  • +1。为什么我们需要在“def default(self, obj)”的末尾添加一行“return json.JSONEncoder.default(self, obj)”?
【解决方案4】:

你可以使用Pandas:

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

【讨论】:

  • 太棒了!而且我认为对于 2D np.array 它将类似于pd.DataFrame(your_array).to_json('data.json', orient='split')
  • 拯救了这一天。谢谢
【解决方案5】:

使用json.dumpsdefaultkwarg:

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)

【讨论】:

  • 那行type(obj).__module__ == np.__name__:有什么作用?检查实例还不够吗?
  • @RamonMartinez,要知道该对象是一个 numpy 对象,这样我就可以将.item 用于几乎任何 numpy 对象。 default 函数为所有未知类型调用 json.dumps 尝试序列化。不仅仅是numpy
  • 我认为这也有助于stackoverflow.com/questions/69920913/… 尽管拥有一个干净的嵌套版本也会很好
【解决方案6】:

默认情况下不支持此功能,但您可以轻松实现!如果您想要返回完全相同的数据,您需要对几件事进行编码:

  • 数据本身,您可以使用@travelingbones 提到的obj.tolist() 获得。有时这可能就足够了。
  • 数据类型。我觉得这在某些情况下很重要。
  • 维度(不一定是 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))

【讨论】:

    【解决方案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】:

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

        【讨论】:

          【解决方案10】:

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

          值得注意的是,一旦我将数组转换为列表,然后将其保存到 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')
          

          希望这会有所帮助!

          【讨论】:

            【解决方案11】:

            这是一个适用于我的实现并删除了所有 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
            

            【讨论】:

              【解决方案12】:

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

              vec_xvec_y 是 numpy 数组:

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

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

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

              【讨论】:

                【解决方案13】:

                可以用检查类型做简单的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()
                

                【讨论】:

                  【解决方案14】:

                  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) 这行代码生成输出 数组数据类型,当您尝试将数组转换为 json 格式时,它是不可能的

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

                  预测 = loaded_model.predict(d)
                  listtype = prediction.tolist() 返回 jsonify(listtype)

                  轰!终于得到了预期的输出,

                  【讨论】:

                    猜你喜欢
                    • 1970-01-01
                    • 2018-06-26
                    • 2013-04-26
                    • 1970-01-01
                    • 2015-07-10
                    • 1970-01-01
                    • 2015-01-07
                    相关资源
                    最近更新 更多