NumPy 字節(jié)交換

2021-09-01 10:25 更新

1、字節(jié)排序和 ndarrays 介紹

ndarray是一個(gè)對(duì)象,在存儲(chǔ)器提供一個(gè)python陣列接口到數(shù)據(jù)。 經(jīng)常發(fā)生的情況是,您要使用數(shù)組查看的內(nèi)存與運(yùn)行 Python 的計(jì)算機(jī)的字節(jié)順序不同。 例如,我可能正在使用小端 CPU 的計(jì)算機(jī)(例如 Intel Pentium)工作,但我從大端計(jì)算機(jī)編寫的文件中加載了一些數(shù)據(jù)。假設(shè)我從 Sun(大端)計(jì)算機(jī)編寫的文件中加載了 4 個(gè)字節(jié)。我知道這 4 個(gè)字節(jié)代表兩個(gè) 16 位整數(shù)。在 big-endian 機(jī)器上,首先存儲(chǔ)一個(gè)兩字節(jié)整數(shù),最高有效字節(jié) (MSB),然后是最低有效字節(jié) (LSB)。因此,字節(jié)按內(nèi)存順序排列:

  1. MSB 整數(shù) 1
  2. LSB 整數(shù) 1
  3. MSB 整數(shù) 2
  4. LSB 整數(shù) 2

假設(shè)這兩個(gè)整數(shù)實(shí)際上是 1 和 770。因?yàn)?770 = 256 * 3 + 2,內(nèi)存中的 4 個(gè)字節(jié)將分別包含:0、1、3、2。我從文件中加載的字節(jié)將包含這些內(nèi)容:

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

我們可能想使用 anndarray來(lái)訪問(wèn)這些整數(shù)。在這種情況下,我們可以圍繞這個(gè)內(nèi)存創(chuàng)建一個(gè)數(shù)組,并告訴 numpy 有兩個(gè)整數(shù),它們是 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上面的數(shù)組>i2。的>意思是“大端”(<是小端)和i2手段“簽訂2字節(jié)整數(shù)”。例如,如果我們的數(shù)據(jù)表示單個(gè)無(wú)符號(hào) 4 字節(jié)小端整數(shù),則 dtype 字符串將為<u4.

事實(shí)上,我們?yōu)槭裁床辉囋嚹兀?/p>

>>> 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- 在這種情況下,我們的基礎(chǔ)數(shù)據(jù)是大端(數(shù)據(jù)端)并且我們已將 dtype 設(shè)置為匹配(dtype 也是大端)。但是,有時(shí)您需要翻轉(zhuǎn)它們。

警告
標(biāo)量當(dāng)前不包括字節(jié)順序信息,因此從數(shù)組中提取標(biāo)量將返回一個(gè)按本機(jī)字節(jié)順序排列的整數(shù)。因此:

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

2、改變字節(jié)順序

從介紹中可以想象,有兩種方法可以影響數(shù)組的字節(jié)順序與其所查看的底層內(nèi)存之間的關(guān)系:

  • 更改數(shù)組 dtype 中的字節(jié)順序信息,以便它將基礎(chǔ)數(shù)據(jù)解釋為不同的字節(jié)順序。這是角色arr.newbyteorder()
  • 更改底層數(shù)據(jù)的字節(jié)順序,保持 dtype 解釋不變。這就是arr.byteswap()它的作用。

需要更改字節(jié)順序的常見情況是:

  1. 您的數(shù)據(jù)和 dtype 字節(jié)序不匹配,并且您想要更改 dtype 以使其與數(shù)據(jù)匹配。
  2. 您的數(shù)據(jù)和 dtype 字節(jié)序不匹配,并且您想交換數(shù)據(jù)以便它們與 dtype 匹配
  3. 您的數(shù)據(jù)和 dtype 字節(jié)序匹配,但您希望交換數(shù)據(jù)并且 dtype 反映這一點(diǎn)

2.1數(shù)據(jù)和 dtype 字節(jié)序不匹配,更改 dtype 以匹配數(shù)據(jù)

我們做一些他們不匹配的東西:

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

這種情況的明顯解決方法是更改?? dtype 以提供正確的字節(jié)序:

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

注意數(shù)組在內(nèi)存中沒有改變:

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

2.2 數(shù)據(jù)和類型字節(jié)序不匹配,更改數(shù)據(jù)以匹配 dtype?

如果您需要內(nèi)存中的數(shù)據(jù)按特定順序排列,您可能想要這樣做。例如,您可能正在將內(nèi)存寫入需要特定字節(jié)順序的文件。

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

現(xiàn)在數(shù)組在內(nèi)存中發(fā)生了變化:

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

2.3 數(shù)據(jù)和 dtype 字節(jié)序匹配,交換數(shù)據(jù)和 dtype?

您可能有一個(gè)正確指定的數(shù)組 dtype,但您需要數(shù)組在內(nèi)存中具有相反的字節(jié)順序,并且您希望 dtype 匹配以便數(shù)組值有意義。在這種情況下,您只需執(zhí)行前面的兩個(gè)操作:

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

使用 ndarray astype 方法可以實(shí)現(xiàn)將數(shù)據(jù)轉(zhuǎn)換為特定 dtype 和字節(jié)順序的更簡(jiǎn)單方法:

>>> swapped_end_arr = big_end_arr.astype('<i2')
>>> swapped_end_arr[0]
1
>>> swapped_end_arr.tobytes() == big_end_buffer
False
以上內(nèi)容是否對(duì)您有幫助:
在線筆記
App下載
App下載

掃描二維碼

下載編程獅App

公眾號(hào)
微信公眾號(hào)

編程獅公眾號(hào)