SimpleJSON and NumPy array

后端 未结 9 1351
挽巷
挽巷 2020-12-04 10:56

What is the most efficient way of serializing a numpy array using simplejson?

相关标签:
9条回答
  • 2020-12-04 11:42

    If you want to apply Russ's method to n-dimensional numpy arrays you can try this

    class NumpyAwareJSONEncoder(json.JSONEncoder):
        def default(self, obj):
            if isinstance(obj, numpy.ndarray):
                if obj.ndim == 1:
                    return obj.tolist()
                else:
                    return [self.default(obj[i]) for i in range(obj.shape[0])]
            return json.JSONEncoder.default(self, obj)
    

    This will simply turn a n-dimensional array into a list of lists with depth "n". To cast such lists back into a numpy array, my_nparray = numpy.array(my_list) will work regardless of the list "depth".

    0 讨论(0)
  • 2020-12-04 11:43

    In order to keep dtype and dimension try this:

    import base64
    import json
    import numpy as np
    
    class NumpyEncoder(json.JSONEncoder):
    
        def default(self, obj):
            """If input object is an ndarray it will be converted into a dict 
            holding dtype, shape and the data, base64 encoded.
            """
            if isinstance(obj, np.ndarray):
                if obj.flags['C_CONTIGUOUS']:
                    obj_data = obj.data
                else:
                    cont_obj = np.ascontiguousarray(obj)
                    assert(cont_obj.flags['C_CONTIGUOUS'])
                    obj_data = cont_obj.data
                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
            super(NumpyEncoder, self).default(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
    
    expected = np.arange(100, dtype=np.float)
    dumped = json.dumps(expected, cls=NumpyEncoder)
    result = json.loads(dumped, object_hook=json_numpy_obj_hook)
    
    
    # None of the following assertions will be broken.
    assert result.dtype == expected.dtype, "Wrong Type"
    assert result.shape == expected.shape, "Wrong Shape"
    assert np.allclose(expected, result), "Wrong Values"
    
    0 讨论(0)
  • 2020-12-04 11:44

    Improving On Russ's answer, I would also include the np.generic scalars:

    class NumpyAwareJSONEncoder(json.JSONEncoder):
        def default(self, obj):
            if isinstance(obj, np.ndarray) and obj.ndim == 1:
                    return obj.tolist()
            elif isinstance(obj, np.generic):
                return obj.item()
            return json.JSONEncoder.default(self, obj)
    
    0 讨论(0)
提交回复
热议问题