web-dev-qa-db-ja.com

行列の次元を維持しながらnumpy配列をシリアル化するにはどうすればよいですか?

numpy.array.tostringは、行列の次元に関する情報を保持していないようです( この質問 を参照)。ユーザーにnumpy.array.reshape

この情報を保持しながら、numpy配列をJSON形式にシリアル化する方法はありますか?

注:配列には、int、float、またはboolを含めることができます。転置された配列を期待するのは合理的です。

注2:これは、そのような情報が関連するようになった場合に、streamparseを使用してStormトポロジにnumpy配列を渡す目的で行われています。

34
blz

_pickle.dumps_ または _numpy.save_ エンディアンの問題、不連続な配列、または変なTuple dtypes。エンディアンの問題はおそらく最も重要です。ビッグエンディアンのマシンに配列をロードしたため、array([1])が突然array([16777216])にならないようにする必要があります。おそらくpickleがより便利なオプションですが、saveには独自の利点があります。これは npy format rationale で示されます。

pickleオプション:

_import pickle
a = # some NumPy array
serialized = pickle.dumps(a, protocol=0) # protocol 0 is printable ASCII
deserialized_a = pickle.loads(serialized)
_

_numpy.save_はバイナリ形式を使用し、ファイルに書き込む必要がありますが、StringIOで回避できます:

_a = # any NumPy array
memfile = StringIO.StringIO()
numpy.save(memfile, a)
memfile.seek(0)
serialized = json.dumps(memfile.read().decode('latin-1'))
# latin-1 maps byte n to unicode code point n
_

そして、デシリアライズするには:

_memfile = StringIO.StringIO()
memfile.write(json.loads(serialized).encode('latin-1'))
memfile.seek(0)
a = numpy.load(memfile)
_
40
user2357112

EDIT:質問のコメントを読むとわかるように、このソリューションは「通常の」numpy配列(float、int、bools ...)を扱い、マルチタイプの構造化配列ではありません。

任意の次元とデータ型のnumpy配列をシリアル化するためのソリューション

私が知る限り、numpy配列を任意のデータ型と次元で単純にシリアル化することはできません...しかし、そのデータ型、次元および情報をリスト表現に保存し、JSONを使用してシリアル化することができます。

インポートが必要

import json
import base64

エンコードの場合を使用できます(nparrayは、任意のデータ型および任意の次元のnumpy配列です):

json.dumps([str(nparray.dtype), base64.b64encode(nparray), nparray.shape])

この後、データのJSONダンプ(文字列)を取得します。このデータには、そのデータ型と形状のリスト表現と、base64でエンコードされた配列data/contentsが含まれます。

そしてデコード用これは動作します(encStrはどこかからロードされたエンコードされたJSON文字列です):

# get the encoded json dump
enc = json.loads(encStr)

# build the numpy data type
dataType = numpy.dtype(enc[0])

# decode the base64 encoded numpy array data and create a new numpy array with this data & type
dataArray = numpy.frombuffer(base64.decodestring(enc[1]), dataType)

# if the array had more than one data set it has to be reshaped
if len(enc) > 2:
     dataArray.reshape(enc[2])   # return the reshaped numpy array containing several data sets

JSONダンプは多くの理由で効率的で相互互換性がありますが、any typeおよびany dimensionのnumpy配列を格納およびロードする場合、JSONを取得するだけで予期しない結果になります。

このソリューションは、タイプまたはディメンションに関係なく、numpy配列を格納およびロードし、それを正しく復元します(データタイプ、ディメンション、...)

私は数ヶ月前に自分でいくつかのソリューションを試しましたが、これは私が出会った唯一の効率的で汎用性の高いソリューションでした。

12
daniel451

Msgpack-numpyのコードが役に立ちました。 https://github.com/lebedov/msgpack-numpy/blob/master/msgpack_numpy.py

シリアル化された辞書を少し修正し、base64エンコードを追加して、シリアル化されたサイズを減らしました。

Jsonと同じインターフェイスを使用して(ロード、ダンプを提供)、jsonシリアル化のドロップイン置換を提供できます。

これと同じロジックを拡張して、日時オブジェクトなどの重要な自動シリアル化を追加できます。


[〜#〜] edit [〜#〜]これを行う汎用のモジュール式パーサーを作成しました。 https://github.com/someones/jaweson


私のコードは次のとおりです。

np_json.py

from json import *
import json
import numpy as np
import base64

def to_json(obj):
    if isinstance(obj, (np.ndarray, np.generic)):
        if isinstance(obj, np.ndarray):
            return {
                '__ndarray__': base64.b64encode(obj.tostring()),
                'dtype': obj.dtype.str,
                'shape': obj.shape,
            }
        Elif isinstance(obj, (np.bool_, np.number)):
            return {
                '__npgeneric__': base64.b64encode(obj.tostring()),
                'dtype': obj.dtype.str,
            }
    if isinstance(obj, set):
        return {'__set__': list(obj)}
    if isinstance(obj, Tuple):
        return {'__Tuple__': list(obj)}
    if isinstance(obj, complex):
        return {'__complex__': obj.__repr__()}

    # Let the base class default method raise the TypeError
    raise TypeError('Unable to serialise object of type {}'.format(type(obj)))


def from_json(obj):
    # check for numpy
    if isinstance(obj, dict):
        if '__ndarray__' in obj:
            return np.fromstring(
                base64.b64decode(obj['__ndarray__']),
                dtype=np.dtype(obj['dtype'])
            ).reshape(obj['shape'])
        if '__npgeneric__' in obj:
            return np.fromstring(
                base64.b64decode(obj['__npgeneric__']),
                dtype=np.dtype(obj['dtype'])
            )[0]
        if '__set__' in obj:
            return set(obj['__set__'])
        if '__Tuple__' in obj:
            return Tuple(obj['__Tuple__'])
        if '__complex__' in obj:
            return complex(obj['__complex__'])

    return obj

# over-write the load(s)/dump(s) functions
def load(*args, **kwargs):
    kwargs['object_hook'] = from_json
    return json.load(*args, **kwargs)


def loads(*args, **kwargs):
    kwargs['object_hook'] = from_json
    return json.loads(*args, **kwargs)


def dump(*args, **kwargs):
    kwargs['default'] = to_json
    return json.dump(*args, **kwargs)


def dumps(*args, **kwargs):
    kwargs['default'] = to_json
    return json.dumps(*args, **kwargs)

その後、次のことができるはずです。

import numpy as np
import np_json as json
np_data = np.zeros((10,10), dtype=np.float32)
new_data = json.loads(json.dumps(np_data))
assert (np_data == new_data).all()
4
Rebs

Msgpackのシリアル化パフォーマンスは最高です: http://www.benfrederickson.com/dont-pickle-your-data/

Msgpack-numpyを使用します。 https://github.com/lebedov/msgpack-numpy を参照してください

インストールしてください:

pip install msgpack-numpy

次に:

import msgpack
import msgpack_numpy as m
import numpy as np

x = np.random.Rand(5)
x_enc = msgpack.packb(x, default=m.encode)
x_rec = msgpack.unpackb(x_enc, object_hook=m.decode)
1
thayne

試してくださいtraitschemahttps://traitschema.readthedocs.io/en/latest/

"特性とNumpyを使用して、シリアル化可能な型チェックスキーマを作成します。典型的な使用例では、さまざまな形状と型の複数のNumpy配列を保存します。"

0
SemanticBeeng

人間が読めるようにする必要があり、これがnumpy配列であることを知っている場合:

import numpy as np; 
import json;

a = np.random.normal(size=(50,120,150))
a_reconstructed = np.asarray(json.loads(json.dumps(a.tolist())))
print np.allclose(a,a_reconstructed)
print (a==a_reconstructed).all()

アレイのサイズが大きくなると、おそらく最も効率的ではありませんが、小さいアレイでは機能します。

0
Chris.Wilson