web-dev-qa-db-fra.com

Le tableau NumPy n'est pas sérialisable JSON

Après avoir créé un tableau NumPy et l'avoir enregistré en tant que variable de contexte Django, le message d'erreur suivant s'affiche lors du chargement de la page Web:

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

Qu'est-ce que ça veut dire?

176
Karnivaurus

Je "jsonify" régulièrement np.arrays. Essayez d’abord d’utiliser la méthode ".tolist ()" sur les tableaux, comme ceci:

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

Pour "désélectionner" le tableau, utilisez:

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

Stocker en JSON un numpy.ndarray ou toute composition à liste imbriquée.

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)

Est-ce que la sortie:

(2, 3)
{"a": [[1, 2, 3], [4, 5, 6]], "aa": [2, [2, 3, 4], [[1, 2, 3], [4, 5, 6]]], "bb": [2]}

Pour restaurer à partir de JSON:

json_load = json.loads(json_dump)
a_restored = np.asarray(json_load["a"])
print(a_restored)
print(a_restored.shape)

Est-ce que la sortie:

[[1 2 3]
 [4 5 6]]
(2, 3)
145
karlB

Vous pouvez utiliser Pandas :

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

J'ai trouvé la meilleure solution si vous avez imbriqué des tableaux numpy dans un dictionnaire:

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)

Merci à ce gars .

27
tsveti_iko

Certains des autres encodeurs numpy semblent un peu trop verbeux.

vérifie si l'objet provient du module numpy, si c'est le cas, utilisez ndarray.tolist pour un ndarray ou utilisez _.item_ pour tout autre type spécifique à numpy.

Utilisez le _json.dumps_ default kwarg:

default doit être une fonction appelée pour les objets ne pouvant pas être sérialisés autrement.

_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)
_
13
moshevi

Ce n'est pas supporté par défaut, mais vous pouvez le faire fonctionner assez facilement! Il y a plusieurs choses que vous voudrez encoder si vous voulez récupérer exactement les mêmes données:

  • Les données elles-mêmes, que vous pouvez obtenir avec obj.tolist() comme @travelingbones mentionné. Parfois, cela peut suffire.
  • Le type de données Je pense que c'est important dans de nombreux cas.
  • La dimension (pas nécessairement 2D), qui pourrait être déduite de ce qui précède si vous supposez que l’entrée est toujours une grille "rectangulaire".
  • L'ordre de la mémoire (ligne-ou colonne-majeur). Cela importe peu, mais parfois (p. Ex. Performances), pourquoi ne pas tout sauvegarder?

De plus, votre tableau numpy pourrait faire partie de votre structure de données, par exemple. vous avez une liste avec quelques matrices à l'intérieur. Pour cela, vous pouvez utiliser un encodeur personnalisé qui effectue les opérations ci-dessus.

Cela devrait suffire à mettre en œuvre une solution. Ou vous pouvez utiliser json-tricks qui ne fait que cela (et supporte divers autres types) (disclaimer: je l'ai fait).

pip install json-tricks

Ensuite

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))
5
Mark

J'ai eu un problème similaire avec un dictionnaire imbriqué contenant quelques 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

Vous pouvez également utiliser l'argument default, par exemple:

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

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

Peut faire simple pour boucle avec les types de contrôle:

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) n'est pas JSON sérialisable

L'erreur susmentionnée a été émise lorsque j'ai essayé de transmettre une liste de données à model.predict () alors que j'attendais une réponse au format 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)

Heureusement, nous avons trouvé un indice pour résoudre l’erreur générée. La sérialisation des objets ne s’applique que pour la conversion suivante. Le mappage doit correspondre à la méthode suivante: objet - dict tableau - liste. Chaîne - chaîne entier - entier

Si vous faites défiler vers le haut pour voir le numéro de ligne 10 prediction = chargé_modèle.predict (d) où cette ligne de code générait la sortie du type de données type array, lorsque vous essayez de convertir un tableau au format json, cela n'est pas possible.

Enfin, j'ai trouvé la solution en convertissant simplement la sortie obtenue en liste de types en suivant les lignes de code.

prédiction = chargé_modèle.predict (d)
listtype = prediction.tolist () retourne jsonify (listtype)

Bhoom! enfin obtenu la sortie attendue, enter image description here

1

C'est une réponse différente, mais cela pourrait aider les personnes qui tentent de sauvegarder des données puis de les relire.
Il y a un hickle qui est plus rapide que cornichon et plus facile.
J'ai essayé de le sauvegarder et de le lire dans Pickle Dump, mais en lisant, il y avait beaucoup de problèmes et une perte d'une heure et je ne trouvais toujours pas de solution alors que je travaillais sur mes propres données pour créer un bot bot.

vec_x et vec_y sont des tableaux numpy:

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

Ensuite, il vous suffit de le lire et d’effectuer les opérations suivantes:

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

Voici une implémentation qui fonctionne pour moi et qui supprime tous les nans (en supposant qu'il s'agisse d'objets simples (list ou dict)):

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

En outre, des informations très intéressantes sur les listes et les tableaux dans Python ~> Liste Python ou Tableau - quand utiliser?

Il est à noter qu’une fois que j’ai converti mes tableaux en liste avant de les enregistrer dans un fichier JSON, dès lors que je suis dans mon déploiement, une fois que j'ai lu ce fichier JSON pour une utilisation ultérieure, je peux continuer à l’utiliser sous forme de liste opposé à la reconvertir en tableau).

ET semble en fait plus joli (à mon avis) à l'écran sous forme de liste (séparée par des virgules) par rapport à un tableau (séparé par des virgules) de cette façon.

En utilisant la méthode .tolist () de @ travelingbones ci-dessus, je l'utilise en tant que telle (en détectant quelques erreurs que j'ai trouvées aussi):

ENREGISTRER DICTIONNAIRE

def writeDict(values, name):
    writeName = DIR+name+'.json'
    with open(writeName, "w") as outfile:
        json.dump(values, outfile)

LIRE LE DICTIONNAIRE

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

J'espère que cela t'aides!

1
ntk4