Массив SimpleJSON и NumPy

Каков наиболее эффективный способ сериализации массива numpy с помощью simplejson?

  • Невозможно разобрать простой json с помощью python
  • Как сериализовать объекты db.Model для json?
  • Кодирование Python JSON
  • Самый простой способ сериализации простого объекта класса с simplejson?
  • Получите данные json через url и используйте в python (simplejson)
  • Декодирование json и Iterate через элементы в шаблоне django
  • Как обеспечить, чтобы ключи ключа python были строчными?
  • Чтение JSON из SimpleHTTPServer
  • 9 Solutions collect form web for “Массив SimpleJSON и NumPy”

    Я бы использовал simplejson.dumps(somearray.tolist()) как наиболее удобный подход (если я все еще использовал simplejson вообще, что подразумевает застревание с Python 2.5 или ранее; 2.6 и более поздние simplejson имеют стандартный библиотечный модуль json который работает Точно так же, конечно, я бы использовал это, если бы поддерживаемая версия Python поддерживала его ;-).

    В поисках большей эффективности вы можете подклассифицировать json.JSONEncoder (в json ; я не знаю, предлагали ли ранее simplejson такие возможности настройки), а в методе по defaultnumpy.array случаи numpy.array , в список или кортежи «как раз вовремя». Я вроде бы сомневаюсь, что вы достаточно набрали бы такой подход, с точки зрения производительности, чтобы оправдать усилия.

    Чтобы сохранить dtype и измерение, попробуйте следующее:

     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 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 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" 

    Я нашел этот код подкласса json для сериализации одномерных массивов numpy в словаре. Я попробовал, и это работает для меня.

     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 , вот способ JSON-кодировать массив NumPy, сохраняя форму и тип любого массива NumPy, в том числе с сложным dtype.

     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" 

    Если вы хотите применить метод 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) будет работать независимо от списка «глубина».

    Совершенствуя ответ «Русс», я бы также включил np.generic скаляры :

     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, eg 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) 

    Один быстрый, хотя и не совсем оптимальный способ использования Pandas :

     import pandas as pd pd.Series(your_array).to_json(orient='values') 

    Я только что нашел ответ tlausch на этот вопрос и понял, что он дает почти правильный ответ для моей проблемы, но по крайней мере для меня это не работает в Python 3.5 из-за нескольких ошибок: 1 – бесконечная рекурсия 2 – данные были сохранены как None

    так как я не могу прямо комментировать исходный ответ, вот моя версия:

     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" 
    Python - лучший язык программирования в мире.