Json Encoder AND Decoder für komplexe numpy Arrays

Ich versuche, JSON ein komplexes, neuliches Array zu kodieren, und ich habe hierfür ein Dienstprogramm aus der Astroie ( http://astropy.readthedocs.org/en/latest/_modules/astropy/utils/misc.html#JsonCustomEncoder ) gefunden Zweck:

import numpy as np class JsonCustomEncoder(json.JSONEncoder): """ <cropped for brevity> """ def default(self, obj): if isinstance(obj, (np.ndarray, np.number)): return obj.tolist() elif isinstance(obj, (complex, np.complex)): return [obj.real, obj.imag] elif isinstance(obj, set): return list(obj) elif isinstance(obj, bytes): # pragma: py3 return obj.decode() return json.JSONEncoder.default(self, obj) 

Das funktioniert gut für eine komplexe numpy Array:

  • Wie kann ich ein JSON-Objekt dynamisch mit Python erstellen?
  • Flasche Display Json in einer ordentlichen Weise
  • Wie kann man json-schema machen, um aber ein anderes Feld zu erlauben?
  • Benutzerdefiniertes Json-Format von Pandas DataFrame
  • Python JSON bekommt nur Schlüssel in der ersten Ebene
  • Schreiben Sie das Json-Format mit Pandas Series und DataFrame
  •  test = {'some_key':np.array([1+1j,2+5j, 3-4j])} 

    Als Dumpingerträge:

     encoded = json.dumps(test, cls=JsonCustomEncoder) print encoded >>> {"some key": [[1.0, 1.0], [2.0, 5.0], [3.0, -4.0]]} 

    Das Problem ist, ich bin nicht ein Weg, um diese wieder in ein komplexes Array automatisch zu lesen. Beispielsweise:

     json.loads(encoded) >>> {"some_key": [[1.0, 1.0], [2.0, 5.0], [3.0, -4.0]]} 

    Können Sie mir helfen, herauszufinden, den Weg, um Lasten / Decodierung zu überschreiben, so dass es darauf hinweist, dass dies ein komplexes Array sein muss? IE Anstelle einer Liste von 2-Element-Elementen, sollte es einfach diese wieder in eine komplexe Array. Der JsonCustomDecoder hat keine default() Methode zu überschreiben, und die docs auf encoding haben zu viel jargon für mich.

    3 Solutions collect form web for “Json Encoder AND Decoder für komplexe numpy Arrays”

    Die akzeptierte Antwort ist großartig, hat aber einen Fehler. Es funktioniert nur, wenn Ihre Daten C_CONTIGUOUS sind. Wenn Sie Ihre Daten umsetzen, ist das nicht wahr. Zum Beispiel testen Sie Folgendes:

     A = np.arange(10).reshape(2,5) A.flags # C_CONTIGUOUS : True # F_CONTIGUOUS : False # OWNDATA : False # WRITEABLE : True # ALIGNED : True # UPDATEIFCOPY : False A = A.transpose() #array([[0, 5], # [1, 6], # [2, 7], # [3, 8], # [4, 9]]) loads(dumps(A)) #array([[0, 1], # [2, 3], # [4, 5], # [6, 7], # [8, 9]]) A.flags # C_CONTIGUOUS : False # F_CONTIGUOUS : True # OWNDATA : False # WRITEABLE : True # ALIGNED : True # UPDATEIFCOPY : False 

    Um dies zu beheben, benutze 'np.ascontiguousarray ()' bei der Übergabe des Objekts an den b64encode. Speziell ändern:

     data_b64 = base64.b64encode(obj.data) 

    NACH:

     data_b64 = base64.b64encode(np.ascontiguousarray(obj).data) 

    Wenn ich die Funktion richtig verstehe, dauert es keine Aktion, wenn deine Daten bereits C_CONTIGUOUS sind, so dass der einzige Performance-Hit ist, wenn du F_CONTIGUOUS Daten hast.

    Es ist unklar, wie viel Hilfe Sie mit json Kodierung / Decodierung benötigen, oder mit der Arbeit mit numpy . Zum Beispiel, wie haben Sie das komplexe Array an erster Stelle erstellt?

    Was deine Kodierung getan hat, macht das Array als Liste der Listen. Der Decoder muss das wieder in ein Array des entsprechenden dtype umwandeln. Beispielsweise:

     d = json.loads(encoded) a = np.dot(d['some_key'],np.array([1,1j])) # array([ 1.+1.j, 2.+5.j, 3.-4.j]) 

    Dies ist nicht der einzige Weg, um ein solches Array aus dieser Liste zu erstellen, und es fehlschlägt wahrscheinlich mit allgemeineren Formen, aber es ist ein Anfang.

    Die nächste Aufgabe ist herauszufinden, wann man eine solche Routine benutzt. Wenn Sie wissen, dass Sie ein solches Array erhalten, dann tun Sie einfach diese Decodierung.

    Eine weitere Möglichkeit besteht darin, dem Wörterbuch eine oder mehrere Schlüssel hinzuzufügen, die diese Variable als komplexes Nricray markieren. Ein Schlüssel könnte auch seine Form kodieren (obwohl dies auch aus der Verschachtelung der Liste der Listen ableitbar ist).

    Ist dies in die richtige Richtung? Oder brauchst du bei jedem Schritt weitere Hilfe?


    Eine der Antworten auf diese Frage "SimpleJSON und NumPy Array"

    https://stackoverflow.com/a/24375113/901925

    numpy sowohl die Codierung als auch die Decodierung von numpy Arrays. Es kodiert ein Wörterbuch mit dem Datentyp und der Form und dem Datenpuffer des Arrays. Also die JSON Saite bedeutet nicht viel für einen Menschen. Aber behandeln allgemeine Arrays, einschließlich der mit komplexen dtype.

    expected und dump Drucke sind:

     [ 1.+1.j 2.+5.j 3.-4.j] {"dtype": "complex128", "shape": [3], "__ndarray__": "AAAAAAAA8D8AAAAAAADwPwAAAAAAAABAAAAAAAAAFEAAAAAAAAAIQAAAAAAAABDA"} 

    Die benutzerdefinierte Decodierung erfolgt mit einer object_hook Funktion, die ein dict annimmt und ein Array zurückgibt (wenn möglich).

     json.loads(dumped, object_hook=json_numpy_obj_hook) 

    Nach diesem Modell, hier ist ein grober hook , der jedes JSON-Array in ein np.array , und jeder mit 2 Spalten in ein 1d komplexes Array:

     def numpy_hook(dct): jj = np.array([1,1j]) for k,v in dct.items(): if isinstance(v, list): v = np.array(v) if v.ndim==2 and v.shape[1]==2: v = np.dot(v,jj) dct[k] = v return dct 

    Es wäre besser, ich denke, um einen Wörterbuchschlüssel zu kodieren, um ein numpy array , und ein anderer, um einen complex dtype zu markieren.


    Ich kann den Haken verbessern, um regelmäßige Listen und andere Array-Dimensionen zu behandeln:

     def numpy_hook(dct): jj = np.array([1,1j]) for k,v in dct.items(): if isinstance(v, list): # try to turn list into numpy array v = np.array(v) if v.dtype==object: # not a normal array, don't change it continue if v.ndim>1 and v.shape[-1]==2: # guess it is a complex array # this information should be more explicit v = np.dot(v,jj) dct[k] = v return dct 

    Es behandelt diese Struktur:

     A = np.array([1+1j,2+5j, 3-4j]) B = np.arange(12).reshape(3,4) C = A+BT test = {'id': 'stream id', 'arrays': [{'A': A}, {'B': B}, {'C': C}]} 

    Zurück:

     {u'arrays': [{u'A': array([ 1.+1.j, 2.+5.j, 3.-4.j])}, {u'B': array([[ 0, 1, 2, 3], [ 4, 5, 6, 7], [ 8, 9, 10, 11]])}, {u'C': array([[ 1.+1.j, 6.+5.j, 11.-4.j], [ 2.+1.j, 7.+5.j, 12.-4.j], [ 3.+1.j, 8.+5.j, 13.-4.j], [ 4.+1.j, 9.+5.j, 14.-4.j]])}], u'id': u'stream id'} 

    Jede Mehrheit erfordert, denke ich, Änderungen an der Kodierung, um die Array-Identität explizit zu machen.

    Hier ist meine endgültige Lösung, die von hpauljs Antwort angepasst wurde, und seine Antwort auf diesen Thread: https://stackoverflow.com/a/24375113/901925

    Dies kodiert / decodiert Arrays, die in beliebigen Tiefen in verschachtelten Wörterbüchern, einem beliebigen Datentyp, verschachtelt sind.

     import base64 import json import numpy as np class NumpyEncoder(json.JSONEncoder): def default(self, obj): """ if input object is a ndarray it will be converted into a dict holding dtype, shape and the data base64 encoded """ if isinstance(obj, np.ndarray): data_b64 = base64.b64encode(obj.data) return dict(__ndarray__=data_b64, dtype=str(obj.dtype), shape=obj.shape) # Let the base class default method raise the TypeError return json.JSONEncoder(self, obj) def json_numpy_obj_hook(dct): """ Decodes a previously encoded numpy ndarray with proper shape and dtype :param dct: (dict) json encoded ndarray :return: (ndarray) if input was an encoded ndarray """ if isinstance(dct, dict) and '__ndarray__' in dct: data = base64.b64decode(dct['__ndarray__']) return np.frombuffer(data, dct['dtype']).reshape(dct['shape']) return dct # Overload dump/load to default use this behavior. def dumps(*args, **kwargs): kwargs.setdefault('cls', NumpyEncoder) return json.dumps(*args, **kwargs) def loads(*args, **kwargs): kwargs.setdefault('object_hook', json_numpy_obj_hook) return json.loads(*args, **kwargs) def dump(*args, **kwargs): kwargs.setdefault('cls', NumpyEncoder) return json.dump(*args, **kwargs) def load(*args, **kwargs): kwargs.setdefault('object_hook', json_numpy_obj_hook) return json.load(*args, **kwargs) if __name__ == '__main__': data = np.arange(3, dtype=np.complex) one_level = {'level1': data, 'foo':'bar'} two_level = {'level2': one_level} dumped = dumps(two_level) result = loads(dumped) print '\noriginal data', data print '\nnested dict of dict complex array', two_level print '\ndecoded nested data', result 

    Welche Ausbeute:

     original data [ 0.+0.j 1.+0.j 2.+0.j] nested dict of dict complex array {'level2': {'level1': array([ 0.+0.j, 1.+0.j, 2.+0.j]), 'foo': 'bar'}} decoded nested data {u'level2': {u'level1': array([ 0.+0.j, 1.+0.j, 2.+0.j]), u'foo': u'bar'}} 
    Python ist die beste Programmiersprache der Welt.