web-dev-qa-db-ja.com

NumPy配列はJSONシリアライズ可能ではありません

NumPy配列を作成し、それをDjangoコンテキスト変数として保存すると、Webページを読み込むときに次のエラーが表示されます。

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

これは何を意味するのでしょうか?

160
Karnivaurus

私は定期的にnp.arraysを "jsonify"します。このように、最初に配列に対して ".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)
206
travelingbones

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)
126
karlB

あなたは Pandas を使うことができます:

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

あなたが辞書に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)

ありがとう この男

24
tsveti_iko

他のぎこちないエンコーダのいくつかは少し過度に冗長に見えます。

もしオブジェクトがモジュールから派手であるかどうかを調べ、そうであれば、ndarrayndarray.tolist を使うか、他の派手な特定の型に.itemを使ってください。

json.dumpsdefault 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)
11
moshevi

これはデフォルトではサポートされていませんが、簡単に機能させることができます。まったく同じデータを元に戻したい場合は、エンコードしたいことがいくつかあります。

  • @travelingbonesが述べたようにあなたがobj.tolist()で得ることができるデータ自体。時にはこれで十分かもしれません。
  • データ型私はこれがかなりの場合重要であると感じます。
  • 次元(必ずしも2次元ではありません)。入力が実際には常に「長方形」のグリッドであると仮定した場合に上記から導き出すことができます。
  • メモリの順番(行または列)。これはあまり重要ではありませんが、場合によっては(パフォーマンスなど)、すべてを保存しないのはなぜですか?

さらに、あなたのでこぼこした配列はあなたのデータ構造の一部になる可能性があります。内部にいくつかの行列を含むリストがあります。そのためにあなたは基本的に上記をするカスタムエンコーダを使うことができます。

解決策を実装するにはこれで十分なはずです。あるいは、 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))
4
Mark

いくつかの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
3
JLT

例えばdefault引数を使うこともできます。

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

json.dump(data, default=myconverter)
3
steco

型をチェックする単純な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()
1
Robert GRZELKA

TypeError:array([[0.46872085、0.67374235、1.0218339、0.13210179、0.5440686、0.9140083、0.58720225、0.2199381]]、dtype = float32)はJSONシリアライズ可能ではありません

私はJSON形式で応答を期待していたときにmodel.predict()にデータのリストを渡そうとしたときに上記のエラーがスローされました。

> 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 string - string integer - integer

スクロールアップして行番号10を表示する場合、このコード行で配列datatype型の出力が生成されていた行を予測= load_model.predict(d)とします。配列をjson形式に変換しようとすると不可能になります。

最後に、得られた出力を次のコード行で型リストに変換することで解決策を見つけました。

予測= loaded_model.predict(d)
listtype = predict.tolist()return jsonify(listtype)

ブーム!ついに期待通りの出力を得ました、 enter image description here

これは別の答えですが、これはデータを保存してからもう一度読み込もうとしている人々を助けるのに役立つかもしれません。
ピクルスより速くて簡単なヒックルがあります。
私はそれをピクルスダンプに保存して読み込もうとしましたが、読んでいる間に多くの問題があり、1時間浪費しました。

vec_xvec_yは派手な配列です。

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

それからあなたはそれを読んで、そして操作を実行するだけです:

data2 = hkl.load( 'new_data_file.hkl' )
1
KS HARSHA

これは私のために働き、すべてのナンを削除する実装です(これらが単純なオブジェクト(リストか辞書)であると仮定して):

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
1
Roei Bahumi

また、Pythonのリストと配列に関するさらに興味深い情報がいくつかあります。〜> Python List vs. Array - いつ使用するか?

配列をJSONファイルに保存する前にリストに変換した後は、いずれにせよ今のところ私のデプロイメントでは、後でそのJSONファイルを使用するためにリスト形式で使用することができますそれを配列に戻すのではなく)。

AND(コンマ区切り)対アレイ(非コンマ区切り)のように、実際には(私の意見では)画面上では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')

お役に立てれば!

1
ntk4