467 Stimmen

NumPy-Array ist nicht JSON-serialisierbar

Nachdem ich ein NumPy-Array erstellt und es als Django-Kontextvariable gespeichert habe, erhalte ich beim Laden der Webseite folgenden Fehler:

array([   0,  239,  479,  717,  952, 1192, 1432, 1667], dtype=int64) ist nicht JSON-serialisierbar

Was bedeutet das?

8voto

Mark Punkte 16672

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

  • Die Daten selbst, die Sie mit obj.tolist() abrufen können, wie von @travelingbones erwähnt. Manchmal ist dies vielleicht gut genug.
  • Der Datentyp. Ich denke, das ist in einigen Fällen wichtig.
  • Die Dimension (nicht unbedingt 2D), die aus dem Vorherigen abgeleitet werden könnte, wenn Sie annehmen, dass die Eingabe tatsächlich immer ein 'rechteckiges' Gitter ist.
  • Die Speicherreihenfolge (zeilen- oder spaltenweise). Dies spielt zwar nicht oft eine Rolle, aber manchmal schon (z.B. Leistung), also warum nicht alles speichern?

Außerdem könnte Ihr Numpy-Array Teil Ihrer Datenstruktur sein, z.B. haben Sie eine Liste mit einigen Matrizen darin. Dafür könnten Sie einen benutzerdefinierten Encoder verwenden, der im Wesentlichen das oben Genannte tut.

Dies sollte ausreichen, um eine Lösung zu implementieren. Oder Sie könnten json-tricks verwenden, das genau dies tut (und verschiedene andere Typen unterstützt) (Haftungsausschluss: Ich habe es gemacht).

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}),  # später ansehen
    set(range(7)),
]
# Mit Metadaten encodieren, um die Typen beim Decodieren beizubehalten
print(dumps(data))

6voto

JLT Punkte 672

Ich hatte ein ähnliches Problem mit einem verschachtelten Wörterbuch, das einige numpy.ndarrays enthielt.

def jsonify(data):
    json_data = dict()
    for key, value in data.iteritems():
        if isinstance(value, list): # für Listen
            value = [ jsonify(item) if isinstance(item, dict) else item for item in value ]
        if isinstance(value, dict): # für verschachtelte Listen
            value = jsonify(value)
        if isinstance(key, int): # wenn der Schlüssel ein Integer ist: > zu String
            key = str(key)
        if type(value).__module__=='numpy': # wenn der Wert numpy.* ist: > zu Python Liste
            value = value.tolist()
        json_data[key] = value
    return json_data

4voto

steco Punkte 1293

Sie könnten auch das default Argument verwenden, zum Beispiel:

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

json.dump(data, default=myconverter)

4voto

Jeff Hykin Punkte 1035

Die anderen Antworten werden nicht funktionieren, wenn der Code einer anderen Person (z.B. ein Modul) das json.dumps() ausführt. Dies geschieht oft, zum Beispiel bei Webservers, die ihre Rückgaberesponses automatisch in JSON umwandeln, was bedeutet, dass wir die Argumente für json.dump() nicht immer ändern können.

Diese Antwort löst das Problem und basiert auf einer (relativ) neuen Lösung, die für jede 3rd-Party-Klasse funktioniert (nicht nur für numpy).

TLDR

pip install json_fix

import json_fix # importiere dies jederzeit bevor JSON.dumps aufgerufen wird
import json

# Erstelle einen Konverter
import numpy
json.fallback_table[numpy.ndarray] = lambda array: array.tolist()

# keine zusätzlichen Argumente erforderlich:
json.dumps(
   dict(thing=10, nested_data=numpy.array((1,2,3)))
)
#>>> '{"thing": 10, "nested_data": [1, 2, 3]}'

2voto

ntk4 Punkte 1149

Außerdem enthält der Link weitere interessante Informationen zum Thema Listen vs. Arrays in Python ~> Python List vs. Array - wann verwenden?

Es könnte darauf hingewiesen werden, dass ich meine Arrays vor dem Speichern in einer JSON-Datei in eine Liste umwandle. In meiner aktuellen Bereitstellung kann ich, sobald ich diese JSON-Datei später zum späteren Gebrauch lese, sie weiterhin in Listenform verwenden (anstatt sie zurück in ein Array zu konvertieren).

Außerdem sieht es (meiner Meinung nach) auf dem Bildschirm als Liste (durch Kommas getrennt) im Vergleich zu einem Array (nicht durch Kommas getrennt) besser aus.

Bei der Verwendung der .tolist() Methode von @travelingbones habe ich dies so gemacht (einige Fehler, die ich auch gefunden habe, abfangen):

DICTIONARY SPEICHERN

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

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

Hoffentlich hilft das!

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X