numpy.array.tostring
似乎没有保留有关矩阵维度的信息(请参阅this question),要求用户发出对numpy.array.reshape
的调用。
有没有办法将numpy数组序列化为JSON格式,同时保留这些信息?
注意:数组可能包含整数,浮点数或布尔值。期望转置数组是合理的。
注2:这样做的目的是使用streamparse将numpy数组传递给Storm拓扑,以防这些信息最终变得相关。
pickle.dumps
或numpy.save
编码重建任意NumPy数组所需的所有信息,即使存在字节序问题,非连续数组或奇怪的元组dtypes。字节序问题可能是最重要的;你不希望array([1])
突然变成array([16777216])
,因为你在大端机器上加载了你的阵列。 pickle
可能是更方便的选择,虽然save
有自己的好处,在npy
format rationale给出。
pickle
选项:
import pickle
a = # some NumPy array
serialized = pickle.dumps(a, protocol=0) # protocol 0 is printable ASCII
deserialized_a = pickle.loads(serialized)
numpy.save
使用二进制格式,它需要写入文件,但你可以用StringIO
解决这个问题:
a = # any NumPy array
memfile = StringIO.StringIO()
numpy.save(memfile, a)
memfile.seek(0)
serialized = json.dumps(memfile.read().decode('latin-1'))
# latin-1 maps byte n to unicode code point n
并反序列化:
memfile = StringIO.StringIO()
memfile.write(json.loads(serialized).encode('latin-1'))
memfile.seek(0)
a = numpy.load(memfile)
编辑:正如人们可以在问题的评论中读到这个解决方案处理“正常”numpy数组(浮点数,整数,布尔...)而不是多类型结构化数组。
用于序列化任何维度和数据类型的numpy数组的解决方案
据我所知,你不能简单地序列化任何数据类型和任何维度的numpy数组......但你可以将它的数据类型,维度和信息存储在列表表示中,然后使用JSON序列化它。
需要进口:
import json
import base64
对于编码,您可以使用(nparray
是任何数据类型和任何维度的一些numpy数组):
json.dumps([str(nparray.dtype), base64.b64encode(nparray), nparray.shape])
在此之后,您将获得数据的JSON转储(字符串),其中包含其数据类型和形状的列表表示以及数据/内容base64编码。
而对于解码,这工作(encStr
是编码的JSON字符串,从某处加载):
# get the encoded json dump
enc = json.loads(encStr)
# build the numpy data type
dataType = numpy.dtype(enc[0])
# decode the base64 encoded numpy array data and create a new numpy array with this data & type
dataArray = numpy.frombuffer(base64.decodestring(enc[1]), dataType)
# if the array had more than one data set it has to be reshaped
if len(enc) > 2:
dataArray.reshape(enc[2]) # return the reshaped numpy array containing several data sets
由于许多原因,JSON转储是高效且交叉兼容的,但如果要存储和加载任何类型和任何维度的numpy数组,则只需使用JSON就会导致意外结果。
此解决方案存储和加载numpy数组,无论其类型或维度如何,并且还可以正确地恢复它(数据类型,维度......)
几个月前我尝试了几种解决方案,这是我遇到的唯一高效,多功能的解决方案。
我发现Msgpack-numpy中的代码很有帮助。 https://github.com/lebedov/msgpack-numpy/blob/master/msgpack_numpy.py
我稍微修改了序列化的dict并添加了base64编码以减少序列化的大小。
通过使用与json(提供load(s),dump(s))相同的接口,您可以为json序列化提供替代。
可以扩展相同的逻辑以添加任何自动的非平凡序列化,例如datetime对象。
编辑我写了一个通用的,模块化的解析器来完成这个以及更多。 https://github.com/someones/jaweson
我的代码如下:
哪怕_JSON.朋友
from json import *
import json
import numpy as np
import base64
def to_json(obj):
if isinstance(obj, (np.ndarray, np.generic)):
if isinstance(obj, np.ndarray):
return {
'__ndarray__': base64.b64encode(obj.tostring()),
'dtype': obj.dtype.str,
'shape': obj.shape,
}
elif isinstance(obj, (np.bool_, np.number)):
return {
'__npgeneric__': base64.b64encode(obj.tostring()),
'dtype': obj.dtype.str,
}
if isinstance(obj, set):
return {'__set__': list(obj)}
if isinstance(obj, tuple):
return {'__tuple__': list(obj)}
if isinstance(obj, complex):
return {'__complex__': obj.__repr__()}
# Let the base class default method raise the TypeError
raise TypeError('Unable to serialise object of type {}'.format(type(obj)))
def from_json(obj):
# check for numpy
if isinstance(obj, dict):
if '__ndarray__' in obj:
return np.fromstring(
base64.b64decode(obj['__ndarray__']),
dtype=np.dtype(obj['dtype'])
).reshape(obj['shape'])
if '__npgeneric__' in obj:
return np.fromstring(
base64.b64decode(obj['__npgeneric__']),
dtype=np.dtype(obj['dtype'])
)[0]
if '__set__' in obj:
return set(obj['__set__'])
if '__tuple__' in obj:
return tuple(obj['__tuple__'])
if '__complex__' in obj:
return complex(obj['__complex__'])
return obj
# over-write the load(s)/dump(s) functions
def load(*args, **kwargs):
kwargs['object_hook'] = from_json
return json.load(*args, **kwargs)
def loads(*args, **kwargs):
kwargs['object_hook'] = from_json
return json.loads(*args, **kwargs)
def dump(*args, **kwargs):
kwargs['default'] = to_json
return json.dump(*args, **kwargs)
def dumps(*args, **kwargs):
kwargs['default'] = to_json
return json.dumps(*args, **kwargs)
您应该能够执行以下操作:
import numpy as np
import np_json as json
np_data = np.zeros((10,10), dtype=np.float32)
new_data = json.loads(json.dumps(np_data))
assert (np_data == new_data).all()
Msgpack具有最佳的序列化性能:http://www.benfrederickson.com/dont-pickle-your-data/
使用msgpack-numpy。见https://github.com/lebedov/msgpack-numpy
安装它:
pip install msgpack-numpy
然后:
import msgpack
import msgpack_numpy as m
import numpy as np
x = np.random.rand(5)
x_enc = msgpack.packb(x, default=m.encode)
x_rec = msgpack.unpackb(x_enc, object_hook=m.decode)
如果它需要人类可读,你知道这是一个numpy数组:
import numpy as np;
import json;
a = np.random.normal(size=(50,120,150))
a_reconstructed = np.asarray(json.loads(json.dumps(a.tolist())))
print np.allclose(a,a_reconstructed)
print (a==a_reconstructed).all()
当数组大小变大时,可能不是最有效的,但适用于较小的数组。
试试traitschema
https://traitschema.readthedocs.io/en/latest/
“使用traits和Numpy创建可序列化,类型检查的模式。典型的用例包括保存几个不同形状和类型的Numpy数组。”
尝试使用numpy.array_repr
或numpy.array_str
。