阅读(1439) (0)

NumPy 字节交换

2021-09-01 10:20:33 更新

1、字节排序和 ndarrays 介绍

ndarray是一个对象,在存储器提供一个python阵列接口到数据。 经常发生的情况是,您要使用数组查看的内存与运行 Python 的计算机的字节顺序不同。 例如,我可能正在使用小端 CPU 的计算机(例如 Intel Pentium)工作,但我从大端计算机编写的文件中加载了一些数据。假设我从 Sun(大端)计算机编写的文件中加载了 4 个字节。我知道这 4 个字节代表两个 16 位整数。在 big-endian 机器上,首先存储一个两字节整数,最高有效字节 (MSB),然后是最低有效字节 (LSB)。因此,字节按内存顺序排列:

  1. MSB 整数 1
  2. LSB 整数 1
  3. MSB 整数 2
  4. LSB 整数 2

假设这两个整数实际上是 1 和 770。因为 770 = 256 * 3 + 2,内存中的 4 个字节将分别包含:0、1、3、2。我从文件中加载的字节将包含这些内容:

>>> big_end_buffer = bytearray([0,1,3,2])
>>> big_end_buffer
bytearray(b'\\x00\\x01\\x03\\x02')

我们可能想使用 anndarray来访问这些整数。在这种情况下,我们可以围绕这个内存创建一个数组,并告诉 numpy 有两个整数,它们是 16 位和 big-endian:

>>> import numpy as np
>>> big_end_arr = np.ndarray(shape=(2,),dtype='>i2', buffer=big_end_buffer)
>>> big_end_arr[0]
1
>>> big_end_arr[1]
770

注意dtype上面的数组>i2。的>意思是“大端”(<是小端)和i2手段“签订2字节整数”。例如,如果我们的数据表示单个无符号 4 字节小端整数,则 dtype 字符串将为<u4.

事实上,我们为什么不试试呢?

>>> little_end_u4 = np.ndarray(shape=(1,),dtype='<u4', buffer=big_end_buffer)
>>> little_end_u4[0] == 1 * 256**1 + 3 * 256**2 + 2 * 256**3
True

回到我们的big_end_arr- 在这种情况下,我们的基础数据是大端(数据端)并且我们已将 dtype 设置为匹配(dtype 也是大端)。但是,有时您需要翻转它们。

警告
标量当前不包括字节顺序信息,因此从数组中提取标量将返回一个按本机字节顺序排列的整数。因此:

&& big_end_arr[0].dtype.byteorder == little_end_u4[0].dtype.byteorder
True

2、改变字节顺序

从介绍中可以想象,有两种方法可以影响数组的字节顺序与其所查看的底层内存之间的关系:

  • 更改数组 dtype 中的字节顺序信息,以便它将基础数据解释为不同的字节顺序。这是角色arr.newbyteorder()
  • 更改底层数据的字节顺序,保持 dtype 解释不变。这就是arr.byteswap()它的作用。

需要更改字节顺序的常见情况是:

  1. 您的数据和 dtype 字节序不匹配,并且您想要更改 dtype 以使其与数据匹配。
  2. 您的数据和 dtype 字节序不匹配,并且您想交换数据以便它们与 dtype 匹配
  3. 您的数据和 dtype 字节序匹配,但您希望交换数据并且 dtype 反映这一点

2.1数据和 dtype 字节序不匹配,更改 dtype 以匹配数据

我们做一些他们不匹配的东西:

>>> wrong_end_dtype_arr = np.ndarray(shape=(2,),dtype='<i2', buffer=big_end_buffer)
>>> wrong_end_dtype_arr[0]
256

这种情况的明显解决方法是更改​​ dtype 以提供正确的字节序:

>>> fixed_end_dtype_arr = wrong_end_dtype_arr.newbyteorder()
>>> fixed_end_dtype_arr[0]
1

注意数组在内存中没有改变:

>>> fixed_end_dtype_arr.tobytes() == big_end_buffer
True

2.2 数据和类型字节序不匹配,更改数据以匹配 dtype 

如果您需要内存中的数据按特定顺序排列,您可能想要这样做。例如,您可能正在将内存写入需要特定字节顺序的文件。

>>> fixed_end_mem_arr = wrong_end_dtype_arr.byteswap()
>>> fixed_end_mem_arr[0]
1

现在数组在内存中发生了变化:

>>> fixed_end_mem_arr.tobytes() == big_end_buffer
False

2.3 数据和 dtype 字节序匹配,交换数据和 dtype 

您可能有一个正确指定的数组 dtype,但您需要数组在内存中具有相反的字节顺序,并且您希望 dtype 匹配以便数组值有意义。在这种情况下,您只需执行前面的两个操作:

>>> swapped_end_arr = big_end_arr.byteswap().newbyteorder()
>>> swapped_end_arr[0]
1
>>> swapped_end_arr.tobytes() == big_end_buffer
False

使用 ndarray astype 方法可以实现将数据转换为特定 dtype 和字节顺序的更简单方法:

>>> swapped_end_arr = big_end_arr.astype('<i2')
>>> swapped_end_arr[0]
1
>>> swapped_end_arr.tobytes() == big_end_buffer
False