Simple JSON 및 NumPy 어레이
simplejson을 사용하여 numpy 어레이를 시리얼화하는 가장 효율적인 방법은 무엇입니까?
dtype 및 dimension을 유지하려면 다음을 수행합니다.
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"
나는 사용하고 싶다simplejson.dumps(somearray.tolist())
가장 편리한 접근법으로서 (아직도 사용하고 있다면)simplejson
즉, Python 2.5 또는 그 이전 버전을 사용하는 것을 의미합니다. 2.6 이상에는 표준 라이브러리 모듈이 있습니다.json
같은 방법으로 동작하기 때문에, 사용중의 Python 릴리스가 서포트하고 있는 경우는, 물론 사용하고 싶습니다.;-).
효율성을 높이기 위해 json을 서브클래스로 분류할 수 있습니다.JSONEncoder(입력)json
; 나이든 사람이simplejson
이미 이러한 커스터마이즈 가능성을 제공) 및default
메서드, 특수한 경우 인스턴스numpy.array
"제 때에" 목록이나 튜플로 변환합니다.하지만 이런 식으로 접근하면 충분히 성과를 얻을 수 있을지 의문입니다. 노력을 정당화할 수 있을 것 같습니다.
사전에서 1차원 numpy 배열을 직렬화하기 위한 이 json 서브클래스 코드를 찾았습니다.저도 해봤는데 효과가 있어요.
class NumpyAwareJSONEncoder(json.JSONEncoder):
def default(self, obj):
if isinstance(obj, numpy.ndarray) and obj.ndim == 1:
return obj.tolist()
return json.JSONEncoder.default(self, obj)
내 사전은 '결과'이다.data.json 파일에 쓰는 방법은 다음과 같습니다.
j=json.dumps(results,cls=NumpyAwareJSONEncoder)
f=open("data.json","w")
f.write(j)
f.close()
여기에서는 1D NumPy 어레이에서 JSON으로 변환하고 어레이로 되돌리는 방법을 보여 줍니다.
try:
import json
except ImportError:
import simplejson as json
import numpy as np
def arr2json(arr):
return json.dumps(arr.tolist())
def json2arr(astr,dtype):
return np.fromiter(json.loads(astr),dtype)
arr=np.arange(10)
astr=arr2json(arr)
print(repr(astr))
# '[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]'
dt=np.int32
arr=json2arr(astr,dt)
print(repr(arr))
# array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])
Tlausch의 답변을 바탕으로 복잡한 dtype을 포함한 NumPy 어레이의 모양과 dtype을 유지하면서 NumPy 어레이를 JSON 인코딩하는 방법을 소개합니다.
class NDArrayEncoder(json.JSONEncoder):
def default(self, obj):
if isinstance(obj, np.ndarray):
output = io.BytesIO()
np.savez_compressed(output, obj=obj)
return {'b64npz' : base64.b64encode(output.getvalue())}
return json.JSONEncoder.default(self, obj)
def ndarray_decoder(dct):
if isinstance(dct, dict) and 'b64npz' in dct:
output = io.BytesIO(base64.b64decode(dct['b64npz']))
output.seek(0)
return np.load(output)['obj']
return dct
# Make expected non-contiguous structured array:
expected = np.arange(10)[::2]
expected = expected.view('<i4,<f4')
dumped = json.dumps(expected, cls=NDArrayEncoder)
result = json.loads(dumped, object_hook=ndarray_decoder)
assert result.dtype == expected.dtype, "Wrong Type"
assert result.shape == expected.shape, "Wrong Shape"
assert np.array_equal(expected, result), "Wrong Values"
나는 방금 이 질문에 대한 Tlausch의 답을 발견하고 그것이 내 문제에 대한 거의 정확한 답을 제공한다는 것을 깨달았습니다. 그러나 적어도 Python 3.5에서는 몇 가지 오류 때문에 작동하지 않습니다: 1 - 무한 재귀 2 - 데이터가 없음으로 저장되었습니다.
아직 원래의 답변에 직접 코멘트를 할 수 없기 때문에, 제 버전은 다음과 같습니다.
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.decode('utf-8'),
dtype=str(obj.dtype),
shape=obj.shape)
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"
Russ의 방법을 n차원 numpy 배열에 적용하고 싶다면 이 방법을 사용해 보십시오.
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)
이렇게 하면 n차원 배열이 깊이 "n"의 목록으로 바뀝니다.이러한 리스트를 numpy 배열로 되돌리려면my_nparray = numpy.array(my_list)
는, 「깊이」리스트에 관계없이 동작합니다.
Russ의 답변을 개선하기 위해 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)
이 질문에 대답할 수 있는 것은, 다음의 기능뿐입니다.json.dumps
다음과 같이 합니다.
json.dumps(np.array([1, 2, 3]), default=json_numpy_serializer)
와 함께
import numpy as np
def json_numpy_serialzer(o):
""" Serialize numpy types for json
Parameters:
o (object): any python object which fails to be serialized by json
Example:
>>> import json
>>> a = np.array([1, 2, 3])
>>> json.dumps(a, default=json_numpy_serializer)
"""
numpy_types = (
np.bool_,
# np.bytes_, -- python `bytes` class is not json serializable
# np.complex64, -- python `complex` class is not json serializable
# np.complex128, -- python `complex` class is not json serializable
# np.complex256, -- special handling below
# np.datetime64, -- python `datetime.datetime` class is not json serializable
np.float16,
np.float32,
np.float64,
# np.float128, -- special handling below
np.int8,
np.int16,
np.int32,
np.int64,
# np.object_ -- should already be evaluated as python native
np.str_,
np.timedelta64,
np.uint8,
np.uint16,
np.uint32,
np.uint64,
np.void,
)
if isinstance(o, np.ndarray):
return o.tolist()
elif isinstance(o, numpy_types):
return o.item()
elif isinstance(o, np.float128):
return o.astype(np.float64).item()
# elif isinstance(o, np.complex256): -- no python native for np.complex256
# return o.astype(np.complex128).item() -- python `complex` class is not json serializable
else:
raise TypeError("{} of type {} is not JSON serializable".format(repr(o), type(o)))
검증 완료:
need_addition_json_handeling = (
np.bytes_,
np.complex64,
np.complex128,
np.complex256,
np.datetime64,
np.float128,
)
numpy_types = tuple(set(np.typeDict.values()))
for numpy_type in numpy_types:
print(numpy_type)
if numpy_type == np.void:
# complex dtypes evaluate as np.void, e.g.
numpy_type = np.dtype([('name', np.str_, 16), ('grades', np.float64, (2,))])
elif numpy_type in need_addition_json_handeling:
print('python native can not be json serialized')
continue
a = np.ones(1, dtype=nptype)
json.dumps(a, default=json_numpy_serialzer)
팬더를 이용하는 것은 매우 빠르지만, 실제로는 최적이지는 않습니다.
import pandas as pd
pd.Series(your_array).to_json(orient='values')
언급URL : https://stackoverflow.com/questions/3488934/simplejson-and-numpy-array
'programing' 카테고리의 다른 글
Rabbit 설정 방법스프링 토끼와의 MQ 연결? (0) | 2023.03.28 |
---|---|
Ionic requests는 안드로이드에서만 404를 반환하고 Chrome에서는 정상적으로 동작합니다. (0) | 2023.03.28 |
Flask, ajax 호출 성공 상태 코드를 반환하는 방법 (0) | 2023.03.28 |
wp_syslog_event가 실행되지 않습니다. (0) | 2023.03.28 |
어떻게 하면 Angular JS로 lodash를 작동시킬 수 있을까요? (0) | 2023.03.28 |