首页 > 解决方案 > 在python中使用numpy解包和打包除无符号整数以外的位?

问题描述

我正在尝试使用 python 中的 NumPy 包使用numpy.unpackbits()和函数来打包和解包位。numpy.unpackbits()

以下是这些功能正常工作的方式。

import numpy as np

x = np.unpackbits(np.array(1, dtype='uint8')) # [0 0 0 0 0 0 0 1]
np.packbits(x) # [1]

x = np.unpackbits(np.array(100, dtype='uint8')) # [0 1 1 0 0 1 0 0]
np.packbits(x) # [100]

x = (np.unpackbits(np.array(255, dtype='uint8'))) # [1 1 1 1 1 1 1 1]
np.packbits(x) # [255]

但是,这不适用于大于 255 的值,因为不支持无符号整数。

x = (np.unpackbits(np.array(300, dtype='uint16')))
# TypeError: Expected an input array of unsigned byte data type

我试图让这些解决方案发挥作用,但它们不会产生像上面那样连贯的输出。我也不知道如何“打包”它们。

第一个解决方案:

def unpackbits(x, num_bits):
    if np.issubdtype(x.dtype, np.floating):
        raise ValueError("numpy data type needs to be int-like")
    xshape = list(x.shape)
    x = x.reshape([-1, 1])
    mask = 2**np.arange(num_bits, dtype=x.dtype).reshape([1, num_bits])
    return (x & mask).astype(bool).astype(int).reshape(xshape + [num_bits])

结果如下。

unpackbits(np.array(1, dtype='uint8'), 16) # [1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0] 
# Starts from the right? Why? Should it not be [0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1]?

unpackbits(np.array(100, dtype='uint8'), 16) # [0 0 1 0 0 1 1 0 0 0 0 0 0 0 0 0] 
# Not what I would expect.

unpackbits(np.array(255, dtype='uint8'), 16) # [1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0] 
# Should be [0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1].

unpackbits(np.array(300, dtype='uint8'), 16) # [0 0 1 1 0 1 0 0 0 0 0 0 0 0 0 0] 
# Is 13,312 according the caluclator provided in Windows 10 20H2 quite a way off from 300.

unpackbits(np.array(300, dtype='uint16'), 16) # [0 0 1 1 0 1 0 0 1 0 0 0 0 0 0 0] 
# Now the calculator says the decimal equivalent is 13,440 after changing to 'uint16'.

第二种解决方案:

np.unpackbits(np.array([1], dtype='uint16').view('uint8')) # [0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0] 
# Not what I expected but...
np.unpackbits(np.array([1], dtype='uint8').view('uint8')) # [0 0 0 0 0 0 0 1] 
# ...works as expected with 'uint8'. Why does it behave in such a way?

np.unpackbits(np.array([100], dtype='uint16').view('uint8')) # [0 1 1 0 0 1 0 0 0 0 0 0 0 0 0 0]
np.unpackbits(np.array([100], dtype='uint8').view('uint8')) # [0 1 1 0 0 1 0 0] 
# The same pattern...

np.unpackbits(np.array([255], dtype='uint16').view('uint8')) # [1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0]
np.unpackbits(np.array([255], dtype='uint8').view('uint8')) # [1 1 1 1 1 1 1 1] 
# ...continues

np.unpackbits(np.array([300], dtype='uint16').view('uint8')) # [0 0 1 0 1 1 0 0 0 0 0 0 0 0 0 1] 11,265 according to the calculator.

第三种解决方案:在此处输入链接描述

def unpackbits_2(in_intAr,Nbits):
    ''' convert (numpyarray of uint => array of Nbits bits) for many bits in parallel'''
    inSize_T= in_intAr.shape
    in_intAr_flat=in_intAr.flatten()
    out_NbitAr= np.zeros((len(in_intAr_flat),Nbits))
    for iBits in range(Nbits):
        out_NbitAr[:,iBits]= (in_intAr_flat>>iBits)&1
    out_NbitAr= out_NbitAr.reshape(inSize_T+(Nbits,))
    return out_NbitAr

我已经修改了原始版本以使用 Python 3,结果如下。

unpackbits_2(np.array(1, dtype='uint16'),16) # [1. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0.] 
# What's with the dots? The numbers are still not right.

unpackbits_2(np.array(100, dtype='uint16'),16) # [0. 0. 1. 0. 0. 1. 1. 0. 0. 0. 0. 0. 0. 0. 0. 0.] 
# The binary is 9,728 (excluding the dots) according to the calculator.

unpackbits_2(np.array(255, dtype='uint16'),16) # [1. 1. 1. 1. 1. 1. 1. 1. 0. 0. 0. 0. 0. 0. 0. 0.]

unpackbits_2(np.array(300, dtype='uint16'),16) # [0. 0. 1. 1. 0. 1. 0. 0. 1. 0. 0. 0. 0. 0. 0. 0.] 
# Converting the binary results in 13,440 in base 10.

我也尝试过使用struck.unpack()但无济于事。

对于多种数据类型(uint8、uint16、uint32、uint64、uint128 等),一种将 int 转换为二进制并返回的高性能(因为此操作将执行数百万次)pythonic 方式将不胜感激。例如 uint8: 255 -> [1 1 1 1 1 1 1 1] -> 255; uint16: 255 -> [0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1] -> 255; 等等。

可以为浮点数和字符执行此操作,还是它们不是正确的数据类型?

标签: pythonarraysnumpystructtype-conversion

解决方案


推荐阅读