如何从字节创建一个numpy ndarray?

11

我可以使用myndarray.tobytes()将numpy ndarray转换为bytes。现在,我该如何将其转换回ndarray呢?

使用.tobytes()方法文档中的示例:

>>> x = np.array([[0, 1], [2, 3]])
>>> bytes = x.tobytes()
>>> bytes
b'\x00\x00\x00\x00\x01\x00\x00\x00\x02\x00\x00\x00\x03\x00\x00\x00'

>>> np.some_magic_function_here(bytes)
array([[0, 1], [2, 3]])

3
np.frombuffer()是 NumPy 库中用于从缓冲区创建数组的函数。它将缓冲区解释为包含指定数据类型的连续元素序列,并使用该序列创建一个新的NumPy数组对象。 - sascha
1
或者 np.fromstring。在这两种情况下,如果不是默认的 float 类型,您还需要指定 dtype - ali_m
3个回答

23
为了反序列化字节,你需要使用np.frombuffer()函数。
tobytes()函数将数组序列化为字节,np.frombuffer()函数对字节进行反序列化。
请注意,一旦序列化完成,形状信息就会丢失,这意味着在反序列化后,需要将其重新变回原始形状。
以下是完整示例:
import numpy as np

x = np.array([[0, 1], [2, 3]], np.int8)
bytes = x.tobytes()
# bytes is a raw array, which means it contains no info regarding the shape of x
# let's make sure: we have 4 values with datatype=int8 (one byte per array's item), therefore the length of bytes should be 4bytes
assert len(bytes) == 4, "Ha??? Weird machine..."

deserialized_bytes = np.frombuffer(bytes, dtype=np.int8)
deserialized_x = np.reshape(deserialized_bytes, newshape=(2, 2))
assert np.array_equal(x, deserialized_x), "Deserialization failed..."

9

在您的编辑之后,似乎您正在走错方向!

您不能使用 np.tobytes() 来存储包含所有信息(如形状和类型)的完整数组,仅需要从这些字节中重建即可! 它只会保存原始数据(单元格数值),并按C或Fortran顺序展平。

现在我们不知道您的任务。但您需要基于序列化的东西。有很多方法,最简单的是基于Python的pickle(示例在这里:python3!):

import pickle
import numpy as np

x = np.array([[0, 1], [2, 3]])
print(x)

x_as_bytes = pickle.dumps(x)
print(x_as_bytes)
print(type(x_as_bytes))

y = pickle.loads(x_as_bytes)
print(y)

输出:

[[0 1]
 [2 3]]
 b'\x80\x03cnumpy.core.multiarray\n_reconstruct\nq\x00cnumpy\nndarray\nq\x01K\x00\x85q\x02C\x01bq\x03\x87q\x04Rq\x05(K\x01K\x02K\x02\x86q\x06cnumpy\ndtype\nq\x07X\x02\x00\x00\x00i8q\x08K\x00K\x01\x87q\tRq\n(K\x03X\x01\x00\x00\x00<q\x0bNNNJ\xff\xff\xff\xffJ\xff\xff\xff\xffK\x00tq\x0cb\x89C \x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\x02\x00\x00\x00\x00\x00\x00\x00\x03\x00\x00\x00\x00\x00\x00\x00q\rtq\x0eb.'
<class 'bytes'>
[[0 1]
 [2 3]]

更好的选择是使用joblib的pickle进行大型数组的专门序列化。joblib的函数基于文件对象,可以使用python的BytesIO将其保存到内存中以使用字节字符串。请访问joblibBytesIO以获取更多信息。

2
如果您提前知道要重新创建的维度,可以使用以下代码:numpy.ndarray(<维度>,<数据类型>,<字节(也称为缓冲区)>)
x = numpy.array([[1.0,1.1,1.2,1.3],[2.0,2.1,2.2,2.3],[3.0,3.1,3.2,3.3]],numpy.float64)
#array([[1. , 1.1, 1.2, 1.3],
#       [2. , 2.1, 2.2, 2.3],
#       [3. , 3.1, 3.2, 3.3]])

xBytes = x.tobytes()
#b'\x00\x00\x00\x00\x00\x00\xf0?\x9a\x99\x99\x99\x99\x99\xf1?333333\xf3?\xcd\xcc\xcc\xcc\xcc\xcc\xf4?\x00\x00\x00\x00\x00\x00\x00@\xcd\xcc\xcc\xcc\xcc\xcc\x00@\x9a\x99\x99\x99\x99\x99\x01@ffffff\x02@\x00\x00\x00\x00\x00\x00\x08@\xcd\xcc\xcc\xcc\xcc\xcc\x08@\x9a\x99\x99\x99\x99\x99\t@ffffff\n@'

newX = numpy.ndarray((3,4),numpy.float64,xBytes)
#array([[1. , 1.1, 1.2, 1.3],
#       [2. , 2.1, 2.2, 2.3],
#       [3. , 3.1, 3.2, 3.3]])

另一种方法可能是,如果您将数据存储为字节数组而不是作为整个ndarray的记录,并且您选择的数据从ndarray变化到ndarray,则可以将预数组数据作为字节聚合在Python bytearray中,然后当它达到所需大小时,您已经知道所需的维度,并且可以使用bytearray作为缓冲区提供这些维度/数据类型。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接