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


247

NumPy配列を作成し、それをDjangoコンテキスト変数として保存した後、Webページをロードすると次のエラーが表示されます。

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

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


19
これは、どこかで、jsonモジュールを使用して派手な配列をダンプしようとしていることを意味します。しかし、処理方法を知ってnumpy.ndarrayいるタイプではありませんjson。独自list(your_array)のシリアライザーを作成するか、(より簡単に)jsonを作成しているものに渡す必要があります。
mgilson 2014年

24
Note list(your_array)はネイティブのintではなくnumpy intを返すため、常に機能するとは限りません。your_array.to_list()代わりに使用してください。
ashishsingal 2017年

18
@ashishsingalのコメントに関するメモ。これは、to_list()ではなくyour_array.tolist()である必要があります。
ベガ

回答:


289

私は定期的に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)

2
リストのリストとしてのみ保存できるのはなぜですか?
Nikhil Prabhu

JSONに収まらないメタデータを持っている私にはわからないが、私はnp.array種類を期待する(例えば、それらは、フロートのように、各エントリのデータ型を指定)
travelingbones

1
私はあなたの方法を試しましたが、プログラムはでスタックしているようtolist()です。
Harvett 2018年

2
@frankliuao私が理由を見つけたのはtolist()、データが大きい場合に膨大な時間がかかるためです。
-Harvett

3
@NikhilPrabhu JSONはJavaScript Object Notationであるため、JavaScript言語からの基本的な構成のみを表すことができます:オブジェクト(Python dictに類似)、配列(Pythonリストに類似)、数値、ブール値、文字列、およびnull(Pythonに類似)Nones )。Numpy配列はこれらのものではないため、JSONにシリアル化できません。一部はJSOのような形式(リストのリスト)に変換できます。これがこの答えです。
クリスL.バーンズ

224

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)

26
これは、ボードの上位にあるはずです。これは、一般化可能で適切に抽象化された方法です。ありがとう!
2018年

1
リストからndarrayを取得する簡単な方法はありますか?
DarksteelPenguin

4
@DarksteelPenguinお探しnumpy.asarray()ですか?
aeolus

2
この答えは素晴らしいですし、簡単にシリアル化numpyののfloat32やJSONなどnp.float64値すぎに拡張することができます:if isinstance(obj, np.float32) or isinstance(obj, np.float64): return float(obj)
Bensge

このソリューションでは、リストにすべてのnumpy配列を手動でキャストする必要がありません。
エドゥアルドスファン

43

あなたはパンダを使うことができます:

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

6
すごい!そして、私は2D np.arrayの場合、それはのようなものになると思いますpd.DataFrame(your_array).to_json('data.json', orient='split')
nix 2017

2
日を救った。ありがとう
anurag

38

辞書に入れ子の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)

この男のおかげで。


役立つ回答をありがとう!属性をjsonファイルに書き込みましたが、ロジスティック回帰のパラメーターを読み戻すのに問題があります。この保存されたjsonファイルの「デコーダー」はありますか?
TTZ 2018

もちろん、そのjson裏を読むためにwith open(path, 'r') as f: data = json.load(f)、これを使用できます。これは、データを含む辞書を返します。
tsveti_iko 2018

読み取り用のことjson:そのファイルをと、それの出力をデシリアライズするために、あなたは、この使用することができますdata = json.loads(data)
tsveti_iko

バイトデータ型を処理するには、これを追加する必要がありました。すべてのバイトがutf-8文字列であると想定しています。elif isinstance(obj、(bytes、)):return obj.decode( "utf-8")
林宗一

+1。「def default(self、obj)」の最後に「return json.JSONEncoder.default(self、obj)」という行が必要なのはなぜですか?
ハンス

22

json.dumps defaultkwargを使用します。

デフォルトは、他の方法ではシリアル化できないオブジェクトに対して呼び出される関数でなければなりません。

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、オブジェクトが派手なオブジェクトであることを知るには、この方法.itemでほとんどすべての派手なオブジェクトに使用できます。default関数はjson.dumps、シリアル化するすべての不明なタイプの試行に対して呼び出されます。numpyだけでなく
moshevi

5

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

  • 取得できるデータ自体 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))

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

3

defaultたとえば、引数を使用することもできます。

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

json.dump(data, default=myconverter)

1

また、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')

お役に立てれば!


1

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

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

これは別の答えですが、データを保存してからもう一度読み込もうとしている人を助けるのに役立ちます。
ピクルより速くて簡単なヒックルがあります。
私はそれをピクルスダンプに保存して読み取ろうとしましたが、読み取り中に多くの問題があり、1時間を無駄にしましたが、チャットボットを作成するために自分のデータに取り組んでいましたが、解決策が見つかりませんでした。

vec_xそしてvec_y、numpy配列です:

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

次に、それを読んで操作を実行します。

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

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

1

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)

0

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)

しかし、幸運なことに、スローしていたエラーを解決するためのヒントが見つかりました。オブジェクトのシリアライズは、次の変換にのみ適用できます。マッピングは、次のようになります。オブジェクト-辞書配列-リスト文字列-文字列整数-整数

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

最後に、コード行をたどって取得した出力をタイプリストに変換するだけで解決策を見つけました

予測= loaded_model.predict(d)
リストタイプ=予測.tolist()戻りjsonify(リストタイプ)

ブーム!最終的に期待される出力を得た、 ここに画像の説明を入力してください

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.