我正在尝试将numpy.ndarray转换为base64,然后将其转换回来。 base64库是否可行? 下面非常简单的代码甚至没有按预期工作。 我错过了什么?
import numpy as np
x = np.array([[1, 2, 3], [4, 5, 6]], np.int32)
print(x)
print(type(x))
encoded = base64.b64encode(x)
decoded = base64.b64decode(encoded)
print(decoded)
print(type(decoded))
有没有办法获得原始变量?
一般问题是: 我可以转换"任何"反对二进制字符串,然后转换回原始类型?
我也许可以使用pickle但我需要压缩格式(不在文件中):
之类的东西x_compressed = zipped(pickle.dumps(x))
答案 0 :(得分:3)
我不确定您要完成的任务,但您可以对任何具有bytes
表示的对象进行base-64编码。在您给出的示例中,您将numpy数组编码为base64。
这是因为numpy数组有bytes
形式。您可以通过在数组周围包裹bytes()
或使用.tobytes()
方法来覆盖它。
import numpy as np
x = np.array([1,2,3])
bytes(x)
# returns:
b'\x01\x00\x00\x00\x02\x00\x00\x00\x03\x00\x00\x00'
x.tobytes()
# returns:
b'\x01\x00\x00\x00\x02\x00\x00\x00\x03\x00\x00\x00'
由于我们有一个bytes
表示的数组,您可以将它传递给base64编码器。请注意,如果对象不是类似于字节的对象,则base64
将在编码之前尝试将其转换,如下例所示:
base64.b64encode(x)
# returns
b'AQAAAAIAAAADAAAA'
base64.b64encode(x.tobytes())
# returns
b'AQAAAAIAAAADAAAA'
字节数组没什么特别的。这只是一系列数字!就是这样。你没有恢复numpy数组的原因是因为编码解码过程仍然只是给你x.tobytes()
而不是x
本身的结果。
要获取原始对象,您需要一个可以读取字节序列并返回某种对象的接口。幸运的是,numpy可以通过frombuffer
函数做到这一点。但是,你需要告诉numpy它读取的数组TYPE为字节。
换句话说,你可以有一个int32
数组和一个int16
数组,它们具有相同的字节表示,但要恢复正确的数组,你需要告诉numpy哪个TYPE是正确的。所以你需要某种对象的知识。
x = np.array([1,2,3])
# encode as base 64
x_64 = base64.b64encode(x.tobytes())
# decode back to bytes
x_bytes = base64.b64decode(x_64)
# use numpy to recreate original array of ints
np.frombuffer(x_bytes, dtype=int)
# returns:
np.array([1, 2, 3])
如果要保存对象然后稍后恢复,则该过程称为序列化。有两个非常好的包处理序列化,第一个在标准库中,调用pickle
,第二个称为dill
,可以处理更复杂的对象。
import pickle
x = np.array([1,2,3])
pickled_x = pickle.dumps(x)
# pickled_x is a bytes-object that is a hard to read by humans.
pickle.loads(x)
# returns:
np.array([1, 2, 3])
答案 1 :(得分:1)
base64编码可能不是一个很好的选择。如果您需要在可能由于传统原因限制为ASCII的环境中存储或传输数据,这可能是一个不错的选择。
对于numpy数组,有更简单的方法tostring
和frombuffer
,需要注意的是你需要知道dtype和shape。如果您使用固定尺寸和类型,可以直接使用它:
>>> x
array([[1, 2, 3],
[4, 5, 6]], dtype=int32)
>>> x.tostring()
b'\x01\x00\x00\x00\x02\x00\x00\x00\x03\x00\x00\x00\x04\x00\x00\x00\x05\x00\x00\x00\x06\x00\x00\x00'
>>> np.frombuffer(x.tostring(), dtype=x.dtype).reshape(x.shape)
array([[1, 2, 3],
[4, 5, 6]], dtype=int32)
否则,只需使用numpy的序列化器和解串器np.save
和np.load
,它们将为您处理这些细节:
>>> import io
>>> f = io.BytesIO()
>>> np.save(f, x)
>>> f.getvalue()
b"\x93NUMPY\x01\x00v\x00{'descr': '<i4', 'fortran_order': False, 'shape': (2, 3), } \n\x01\x00\x00\x00\x02\x00\x00\x00\x03\x00\x00\x00\x04\x00\x00\x00\x05\x00\x00\x00\x06\x00\x00\x00"
>>> f.seek(0); np.load(f)
array([[1, 2, 3],
[4, 5, 6]], dtype=int32)
注意:如果需要,您可以随时在这些序列化字节(即f.getvalue()
字符串)上添加b64编码/解码传递 - 但出于所有实际目的,您可能只需要传输numpy的字节直接没有转换为/从b64。
一般问题是:我可以转换&#34;任何&#34;反对二进制字符串,然后转换回原始类型?
理论上,是的,因为无论如何,对象只是计算机上的字节。
对于Python对象的常规序列化,标准库提供pickle
。可以使用zlib
添加压缩,仅举一个例子。