Das NumPy-Array ist nicht JSON-serialisierbar


247

Nach dem Erstellen eines NumPy-Arrays und dem Speichern als Django-Kontextvariable wird beim Laden der Webseite die folgende Fehlermeldung angezeigt:

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

Was bedeutet das?


19
Es bedeutet, dass irgendwo etwas versucht, ein Numpy-Array mit dem jsonModul zu sichern . Ist numpy.ndarrayaber kein Typ, der jsonweiß, wie man damit umgeht. Sie müssen entweder Ihren eigenen Serializer schreiben oder (einfacher) einfach an das übergeben list(your_array), was den JSON schreibt.
mgilson

24
Hinweis list(your_array)funktioniert nicht immer, da es numpy Ints zurückgibt, nicht native Ints. Verwenden Sie your_array.to_list()stattdessen.
Ashishsingal

18
Ein Hinweis zu @ ashishsingals Kommentar sollte your_array.tolist () sein, nicht to_list ().
Vega

Antworten:


289

Ich "jsonify" regelmäßig np.arrays. Versuchen Sie zunächst, die Methode ".tolist ()" für die Arrays wie folgt zu verwenden:

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

Um das Array zu "unjsonifizieren", verwenden Sie:

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

2
Warum kann es nur als Listenliste gespeichert werden?
Nikhil Prabhu

Ich weiß es nicht, aber ich gehe davon aus, dass np.array-Typen Metadaten haben, die nicht in json passen (z. B. geben sie den Datentyp jedes Eintrags wie float an)
travellingbones

1
Ich habe Ihre Methode ausprobiert, aber es scheint, dass das Programm feststeckte tolist().
Harvett

2
@frankliuao Ich fand den Grund dafür, dass es tolist()sehr viel Zeit in Anspruch nimmt, wenn die Daten groß sind.
Harvett

3
@NikhilPrabhu JSON ist eine Javascript-Objektnotation und kann daher nur die Grundkonstrukte aus der Javascript-Sprache darstellen: Objekte (analog zu Python-Diktaten), Arrays (analog zu Python-Listen), Zahlen, Boolesche Werte, Zeichenfolgen und Nullen (analog zu Python-Nones) ). Numpy Arrays gehören nicht dazu und können daher nicht in JSON serialisiert werden. Einige können in eine JSO-ähnliche Form (Liste von Listen) konvertiert werden, was diese Antwort bewirkt.
Chris L. Barnes

224

Speichern Sie als JSON eine numpy.ndarray oder eine beliebige Komposition mit verschachtelten Listen.

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)

Wird ausgegeben:

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

So stellen Sie von JSON wieder her:

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

Wird ausgegeben:

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

26
Dies sollte viel höher liegen, es ist die verallgemeinerbare und richtig abstrahierte Methode, dies zu tun. Vielen Dank!
Thclark

1
Gibt es eine einfache Möglichkeit, den ndarray von der Liste zurückzubekommen?
DarksteelPenguin

4
@ DarksteelPenguin suchst du numpy.asarray()?
Äolus

2
Diese Antwort ist großartig und kann leicht erweitert werden, um numpy float32- und np.float64-Werte auch als json zu serialisieren:if isinstance(obj, np.float32) or isinstance(obj, np.float64): return float(obj)
Bensge

Mit dieser Lösung müssen Sie nicht jedes numpy-Array, das aufgelistet werden soll, manuell umwandeln.
Eduardosufan

43

Sie können Pandas verwenden :

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

6
Toll! Und ich denke für 2D np.array wird es so etwas wie sein pd.DataFrame(your_array).to_json('data.json', orient='split').
Nix

2
Den Tag gerettet. Danke
anurag

38

Ich habe die beste Lösung gefunden, wenn Sie Numpy-Arrays in einem Wörterbuch verschachtelt haben:

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)

Danke an diesen Kerl .


Danke für die hilfreiche Antwort! Ich habe die Attribute in eine JSON-Datei geschrieben, habe aber jetzt Probleme, die Parameter für die logistische Regression zurückzulesen. Gibt es einen 'Decoder' für diese gespeicherte JSON-Datei?
TTZ

Zum Zurücklesen jsonkönnen Sie natürlich Folgendes verwenden : with open(path, 'r') as f: data = json.load(f), das ein Wörterbuch mit Ihren Daten zurückgibt.
Tsveti_iko

Das ist zum Lesen der jsonDatei und zum Deserialisieren der Ausgabe können Sie data = json.loads(data)
Folgendes

Ich musste dies hinzufügen, um den Datentyp Bytes zu verarbeiten. Angenommen, alle Bytes sind utf-8-Zeichenfolgen. elif isinstance (obj, (bytes,)): obj.decode ("utf-8") zurückgeben
Soichi Hayashi

+1. Warum brauchen wir die Zeile "return json.JSONEncoder.default (self, obj)" am Ende von "def default (self, obj)"?
Hans

22

Benutze den json.dumps defaultKwarg:

Standard sollte eine Funktion sein, die für Objekte aufgerufen wird, die sonst nicht serialisiert werden können.

defaultÜberprüfen Sie in der Funktion, ob das Objekt aus dem Modul numpy stammt, wenn ja, verwenden Sie es entweder ndarray.tolistfür einen ndarrayoder .itemfür einen anderen numpy-spezifischen Typ.

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)

Welche Rolle spielt die Linie type(obj).__module__ == np.__name__: dort? Wäre es nicht ausreichend, nach der Instanz zu suchen?
Ramon Martinez

@RamonMartinez, um zu wissen, dass das Objekt ein Numpy-Objekt ist, kann ich es auf diese Weise .itemfür fast jedes Numpy-Objekt verwenden. defaultDie Funktion wird für alle json.dumpsVersuche unbekannter Typen aufgerufen, zu serialisieren. nicht nur numpy
moshevi

5

Dies wird standardmäßig nicht unterstützt, aber Sie können es ganz einfach zum Laufen bringen! Es gibt mehrere Dinge, die Sie codieren möchten, wenn Sie genau dieselben Daten zurückhaben möchten:

  • Die Daten selbst, die Sie mit obj.tolist()@travelingbones erhalten können. Manchmal kann das gut genug sein.
  • Der Datentyp. Ich halte dies in einigen Fällen für wichtig.
  • Die Dimension (nicht unbedingt 2D), die aus dem Obigen abgeleitet werden könnte, wenn Sie annehmen, dass die Eingabe tatsächlich immer ein 'rechteckiges' Gitter ist.
  • Die Speicherreihenfolge (Zeilen- oder Spaltenmajor). Dies ist nicht oft wichtig, aber manchmal auch (z. B. Leistung). Warum also nicht alles speichern?

Darüber hinaus könnte Ihr Numpy-Array Teil Ihrer Datenstruktur sein, z. B. haben Sie eine Liste mit einigen Matrizen. Dafür können Sie einen benutzerdefinierten Encoder verwenden, der im Grunde das oben Genannte tut.

Dies sollte ausreichen, um eine Lösung zu implementieren. Oder Sie könnten json-Tricks verwenden, die genau dies tun (und verschiedene andere Typen unterstützen) (Haftungsausschluss: Ich habe es geschafft).

pip install json-tricks

Dann

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

Ich hatte ein ähnliches Problem mit einem verschachtelten Wörterbuch mit einigen 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

Sie können auch defaultArgumente verwenden, zum Beispiel:

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

json.dump(data, default=myconverter)

1

Außerdem einige sehr interessante Informationen weiter zu Listen vs. Arrays in Python ~> Python List vs. Array - wann verwenden?

Es kann angemerkt werden, dass ich, sobald ich meine Arrays in eine Liste konvertiere, bevor ich sie in einer JSON-Datei speichere, in meiner Bereitstellung, sobald ich diese JSON-Datei zur späteren Verwendung gelesen habe, sie weiterhin in einer Listenform (as) verwenden kann im Gegensatz zur Rückkonvertierung in ein Array).

UND sieht auf dem Bildschirm tatsächlich besser aus (meiner Meinung nach) als Liste (durch Kommas getrennt) im Vergleich zu einem Array (ohne Komma getrennt) auf diese Weise.

Mit der oben genannten .tolist () -Methode von @ travellingbones habe ich sie als solche verwendet (wobei ich auch einige Fehler gefunden habe, die ich gefunden habe):

WÖRTERBUCH SPEICHERN

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

WÖRTERBUCH LESEN

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

Hoffe das hilft!


1

Hier ist eine Implementierung, die für mich funktioniert und alle Nans entfernt hat (vorausgesetzt, es handelt sich um einfache Objekte (Liste oder Diktat)):

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

Dies ist eine andere Antwort, aber dies kann Menschen helfen, die versuchen, Daten zu speichern und sie dann erneut zu lesen.
Es gibt Hickle, das schneller als Pickle und einfacher ist.
Ich habe versucht, es in Pickle Dump zu speichern und zu lesen, aber beim Lesen gab es viele Probleme und es wurde eine Stunde verschwendet und ich fand immer noch keine Lösung, obwohl ich an meinen eigenen Daten arbeitete, um einen Chat-Bot zu erstellen.

vec_xund vec_ysind numpy Arrays:

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

Dann lesen Sie es einfach und führen die Operationen aus:

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

1

Kann einfach für Schleife mit Prüftypen tun:

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

Verwenden Sie NumpyEncoder, um den JSON-Dump erfolgreich zu verarbeiten. Ohne zu werfen - Das NumPy-Array ist nicht JSON-serialisierbar

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) ist nicht JSON-serialisierbar

Der oben erwähnte Fehler wurde ausgelöst, als ich versuchte, die Liste der Daten an model.predict () zu übergeben, als ich die Antwort im JSON-Format erwartete.

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

Glücklicherweise wurde der Hinweis gefunden, um den Fehler zu beheben, der ausgelöst wurde. Die Serialisierung der Objekte gilt nur für die folgende Konvertierung. Die Zuordnung sollte folgendermaßen erfolgen: Objekt - Diktat Array - Liste Zeichenfolge - Zeichenfolge Ganzzahl - Ganzzahl

Wenn Sie nach oben scrollen, um die Zeilennummer 10 zu sehen, wird die Vorhersage = load_model.predict (d) angezeigt, in der diese Codezeile die Ausgabe des Datentyps Array generiert hat. Wenn Sie versuchen, das Array in das JSON-Format zu konvertieren, ist dies nicht möglich

Schließlich fand ich die Lösung, indem ich die erhaltene Ausgabe durch Befolgen der Codezeilen in die Typliste konvertierte

Vorhersage = geladenes_Modell.Prädikt (d)
Listentyp = Vorhersage.Tolist () Rückgabe jsonify (Listentyp)

Bhoom! endlich die erwartete Leistung bekommen, Geben Sie hier die Bildbeschreibung ein

Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.