NumPy字節(jié)交換
字節(jié)排序和ndarrays簡介
ndarray
是一個為內(nèi)存中的數(shù)據(jù)提供python數(shù)組接口的對象。
經(jīng)常發(fā)生的情況是,要用數(shù)組查看的內(nèi)存與運行Python的計算機的字節(jié)順序不同。
例如,我可能正在使用帶有 little-endian CPU 的計算機 - 例如Intel Pentium,但是我已經(jīng)從一個由 big-endian計算機 編寫的文件中加載了一些數(shù)據(jù)。假設(shè)我已經(jīng)從Sun(big-endian)計算機寫入的文件中加載了4個字節(jié)。我知道這4個字節(jié)代表兩個16位整數(shù)。在 big-endian 機器上,首先以最高有效字節(jié)(MSB)存儲雙字節(jié)整數(shù),然后存儲最低有效字節(jié)(LSB)。因此字節(jié)按內(nèi)存順序排列:
- MSB整數(shù)1
- LSB整數(shù)1
- MSB整數(shù)2
- LSB整數(shù)2
假設(shè)兩個整數(shù)實際上是1和770.因為770 = 256 * 3 + 2,內(nèi)存中的4個字節(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')
我們可能需要使用 ndarray
來訪問這些整數(shù)。在這種情況下,我們可以圍繞這個內(nèi)存創(chuàng)建一個數(shù)組,并告訴numpy有兩個整數(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
注意上面的數(shù)組dtype > i2
。>
表示 big-endian
( <
是 Little-endian
),i2
表示‘有符號的2字節(jié)整數(shù)’。例如,如果我們的數(shù)據(jù)表示單個無符號4字節(jié)小端整數(shù),則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
- 在這種情況下我們的基礎(chǔ)數(shù)據(jù)是big-endian(數(shù)據(jù)字節(jié)序),我們設(shè)置dtype匹配(dtype也是big-endian)。但是,有時你需要翻轉(zhuǎn)它們。
警告
標(biāo)量當(dāng)前不包含字節(jié)順序信息,因此從數(shù)組中提取標(biāo)量將返回本機字節(jié)順序的整數(shù)。因此:
>>> big_end_arr[0].dtype.byteorder == little_end_u4[0].dtype.byteorder
True
更改字節(jié)順序
從介紹中可以想象,有兩種方法可以影響數(shù)組的字節(jié)順序與它所查看的底層內(nèi)存之間的關(guān)系:
- 更改數(shù)組dtype中的字節(jié)順序信息,以便將基礎(chǔ)數(shù)據(jù)解釋為不同的字節(jié)順序。這是作用
arr.newbyteorder()
- 更改基礎(chǔ)數(shù)據(jù)的字節(jié)順序,保留dtype解釋。這是做什么的
arr.byteswap()
。
您需要更改字節(jié)順序的常見情況是:
- 您的數(shù)據(jù)和dtype字節(jié)順序不匹配,并且您希望更改dtype以使其與數(shù)據(jù)匹配。
- 您的數(shù)據(jù)和dtype字節(jié)順序不匹配,并且您希望交換數(shù)據(jù)以使它們與dtype匹配
- 您的數(shù)據(jù)和dtype字節(jié)順序匹配,但您希望交換數(shù)據(jù)和dtype來反映這一點
數(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
請注意,內(nèi)存中的數(shù)組未更改:
>>> fixed_end_dtype_arr.tobytes() == big_end_buffer
True
數(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)存中更改:
>>> fixed_end_mem_arr.tobytes() == big_end_buffer
False
數(shù)據(jù)和dtype字節(jié)序匹配,交換數(shù)據(jù)和dtype
您可能有一個正確指定的數(shù)組dtype,但是您需要數(shù)組在內(nèi)存中具有相反的字節(jié)順序,并且您希望dtype匹配以便數(shù)組值有意義。在這種情況下,您只需執(zhí)行上述兩個操作:
>>> swapped_end_arr = big_end_arr.byteswap().newbyteorder()
>>> swapped_end_arr[0]
1
>>> swapped_end_arr.tobytes() == big_end_buffer
False
使用ndarray astype方法可以更簡單地將數(shù)據(jù)轉(zhuǎn)換為特定的dtype和字節(jié)順序:
>>> swapped_end_arr = big_end_arr.astype('<i2')
>>> swapped_end_arr[0]
1
>>> swapped_end_arr.tobytes() == big_end_buffer
False
作者:柯廣的網(wǎng)絡(luò)日志 ? NumPy字節(jié)交換
微信公眾號:Java大數(shù)據(jù)與數(shù)據(jù)倉庫