Comment sérialiser un tableau numpy tout en préservant les dimensions de la matrice?

numpy.array.tostring ne semble pas préserver les informations sur les dimensions de la matrice (voir cette question ), exigeant de l'utilisateur d'émettre un appel à numpy.array.reshape .

y a-t-il un moyen de sérialiser un tableau numpy au format JSON tout en préservant cette information?

Note: les tableaux peuvent contenir des ints, des flotteurs ou des bools. Il est raisonnable de s'attendre à un tableau transposé.

Note 2: ceci est fait avec l'intention de passer le réseau de numpy à travers une topologie de Tempête en utilisant streamparse, au cas où de telles informations finissent par être pertinentes.

24
demandé sur Community 2015-06-07 23:13:50

7 réponses

pickle.dumps ou numpy.save encodent toutes les informations nécessaires à la reconstruction d'un tableau NumPy arbitraire, même en présence de problèmes d'endianthèse, de tableaux non contigus, ou de tuples dtypes bizarres. Les questions d'endianess sont probablement les plus importantes; vous ne voulez pas que array([1]) devienne soudainement array([16777216]) parce que vous avez chargé votre réseau sur une machine big-endian. pickle est probablement l'option la plus commode, bien que save a ses propres avantages, donnés dans le npy justification du format .

l'option 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 utilise un format binaire, et il a besoin d'écrire dans un fichier, mais vous pouvez contourner cela avec 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

et de desérialiser:

memfile = StringIO.StringIO()
memfile.write(json.loads(serialized).encode('latin-1'))
memfile.seek(0)
a = numpy.load(memfile)
30
répondu user2357112 2018-09-03 22:24:18

EDIT: comme on peut le lire dans les commentaires de la question Cette solution traite des tableaux vides" normaux " (flotteurs, bols, etc.)...) et non avec des matrices structurées multi-types.

Solution de sérialisation d'un tableau numpy de toutes les dimensions et les types de données

autant que je sache, vous ne pouvez pas simplement sérialiser un tableau numpy avec n'importe quel type de données et n'importe quelle dimension...mais vous pouvez stocker son type de données, dimension et information dans une représentation de liste et ensuite sérialiser en utilisant JSON.

importations nécessaires :

import json
import base64

Pour l'encodage , vous pouvez utiliser ( nparray est un tableau numpy de tout type de données et de toute dimension):

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

après cela vous obtenez un dump (chaîne) de vos données, contenant une représentation de liste de son type de données et la forme ainsi que le tableaux de données / contenus codés selon la base64.

et pour le décodage ceci fait le travail ( encStr est la chaîne codée JSON, chargée de quelque part):

# 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 dumps sont efficaces et Cross-compatibles pour de nombreuses raisons, mais juste prendre JSON conduit à des résultats inattendus si vous voulez stocker et charger des tableaux vides de n'importe quel type et n'importe quelle dimension .

cette solution stocke et charge des tableaux numpy quel que soit le type ou la dimension et la restaure correctement (type de données, dimension, ...)

j'ai moi-même essayé plusieurs solutions il y a plusieurs mois et c'était la seule solution efficace et polyvalente que j'ai trouvée.

6
répondu daniel451 2015-06-07 21:55:13

j'ai trouvé le code dans Msgpack-num PY utile. https://github.com/lebedov/msgpack-numpy/blob/master/msgpack_numpy.py

j'ai légèrement modifié le DCT sérialisé et ajouté l'encodage base64 pour réduire la taille sérialisée.

en utilisant la même interface que json (fournissant la(Les) charge(s), dump (S)), vous pouvez fournir un remplacement direct pour la sérialisation JSON.

cette même logique peut être étendue pour ajouter toute sérialisation automatique non triviale, comme les objets datetime.


modifier J'ai écrit un analyseur Générique, modulaire, qui fait ceci et plus. https://github.com/someones/jaweson


mon code est le suivant:

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)

vous devriez pouvoir alors faire ce qui suit:

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()
3
répondu Rebs 2015-10-15 02:51:49

si elle doit être lisible par un humain et que vous savez qu'il s'agit d'un numpy array:

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

peut-être pas le plus efficace comme les tailles de tableau plus grand, mais fonctionne pour les tableaux plus petits.

0
répondu Chris.Wilson 2015-12-01 17:19:12

Msgpack a les meilleures performances de sérialisation: http://www.benfrederickson.com/dont-pickle-your-data /

utilisez msgpack-numpy. Voir https://github.com/lebedov/msgpack-numpy

Installer:

pip install msgpack-numpy

puis:

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)
0
répondu thayne 2018-01-19 18:14:59

Try traitschema https://traitschema.readthedocs.io/en/latest /

"Créer serializable, type vérifié sur le schéma à l'aide de traits et de Numpy. Un cas d'utilisation typique implique l'économie de plusieurs tableaux Numpy de forme et de type variables."

0
répondu SemanticBeeng 2018-05-11 13:43:13

essayez numpy.array_repr ou numpy.array_str .

-4
répondu Ken 2015-06-07 20:28:54