用于复杂 numpy 数组的 Json 编码器和解码器 [英] Json Encoder AND Decoder for complex numpy arrays
问题描述
我正在尝试对复杂的 numpy 数组进行 JSON 编码,并且我从 astropy 中找到了一个实用程序(http://astropy.readthedocs.org/en/latest/_modules/astropy/utils/misc.html#JsonCustomEncoder) 为此目的:
I'm trying to JSON encode a complex numpy array, and I've found a utility from astropy (http://astropy.readthedocs.org/en/latest/_modules/astropy/utils/misc.html#JsonCustomEncoder) for this purpose:
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)
这适用于复杂的 numpy 数组:
This works well for a complex numpy array:
test = {'some_key':np.array([1+1j,2+5j, 3-4j])}
作为倾销收益率:
encoded = json.dumps(test, cls=JsonCustomEncoder)
print encoded
>>> {"some key": [[1.0, 1.0], [2.0, 5.0], [3.0, -4.0]]}
问题是,我没有办法自动将其读回复杂数组.例如:
The problem is, I don't a way to read this back into a complex array automatically. For example:
json.loads(encoded)
>>> {"some_key": [[1.0, 1.0], [2.0, 5.0], [3.0, -4.0]]}
你们能帮我找出覆盖加载/解码的方法,以便推断这一定是一个复杂的数组吗?IE.而不是 2 元素项目的列表,它应该只是将它们放回一个复杂的数组中.JsonCustomDecoder 没有要覆盖的 default()
方法,而且关于编码的文档对我来说太多了.
Can you guys help me figure out the way to overwrite loads/decoding so that it infers that this must be a complex array? I.E. Instead of a list of 2-element items, it should just put these back into a complex array. The JsonCustomDecoder doesn't have a default()
method to overwrite, and the docs on encoding have too much jargon for me.
推荐答案
这是我的最终解决方案,改编自 hpaulj 的回答,以及他对此线程的回答:https://stackoverflow.com/a/24375113/901925
Here is my final solution that was adapted from hpaulj's answer, and his answer to this thread: https://stackoverflow.com/a/24375113/901925
这将编码/解码嵌套在任何数据类型的嵌套字典中任意深度的数组.
This will encode/decode arrays that are nested to arbitrary depth in nested dictionaries, of any datatype.
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 '
original data', data
print '
nested dict of dict complex array', two_level
print '
decoded nested data', result
产生输出:
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'}}
这篇关于用于复杂 numpy 数组的 Json 编码器和解码器的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!