Packbits() function of numpy

Overview:

  • The numpy.packbits() function creates integers of type numpy.uint8 from the rows and columns of an ndarray. The reverse is provided by the numpy.unpackbits().

  • If the number of bits are less than eight in a row or column zeros are added to the right.

  • If the axis parameter is 1 bits are taken along the rows. Each byte in a row is packed into an numpy.uint8. Assuming there are 10 bytes in a row - first 8 bits will form an integer and the next two bits will form another integer. Since there are only two bits at the end, six zeroes will be added to the right. 

  • If the axis parameter is 0 the uint objects are formed by taking the bits along the columns of the numpy ndarray. If there are 12 bits in a column the first 8 bits of the column go into a numpy.uint8 object. The remaining 4 bits are padded with zeros to the right and the next numpy.uint8 is formed. 

packbits() function of Python NumPy

Example 1:

# Example Python program that uses numpy packbits()
# function to get an array of numpy.uint8 elements  
# from an ndarray. The function treats the elements 
# of the ndarray as binary bits.

import numpy as np

a1 = np.ndarray(shape = (3, 3), 
                dtype = np.int32)

# Populate array elements
a1[0] = [0, 0, 1]
a1[1] = [0, 1, 0]
a1[2] = [5, 0, 0]

# Create int8 elements
packed = np.packbits(a1, axis=1)
print("Input ndarray:")
print(a1)
print("Shape of input ndarray:")
print(a1.shape)
print("Data type of the input ndarray:")
print(a1.dtype)

print("Array of int8 elements:")
print(packed)
print("Shape of the int8 array:")
print(packed.shape)
print("Data type of the resultant ndarray:")
print(packed.dtype)

Output:

Input ndarray:

[[0 0 1]

 [0 1 0]

 [5 0 0]]

Shape of input ndarray:

(3, 3)

Data type of the input ndarray:

int32

Array of int8 elements:

[[ 32]

 [ 64]

 [128]]

Shape of the int8 array:

(3, 1)

Data type of the resultant ndarray:

uint8

Example 2 - From multiple bytes:

The example has an ndarray of shape (1,9) – one row and nine columns. The bit pattern starts with one and it alternates to zero and the pattern continues till all the nine columns of the row is filled. When numpy.packbits() is called to create integers by packing the bits along the row, it returns an ndarray containing two integers of type numpy.uint8. When numpy.packbits() is called using the same input array with 0 as the value of the axis parameter, it returns one numpy.uint8 for each column thus returning an ndarray of shape (1,9).

# Example program that uses numpy.packbits()
# to create multiple uint objects
# from a row of an ndarray that has more than 8 bits
# (1 byte for 1 uint)

import numpy

# Create an ndarray with two bytes
moreThanAByte = numpy.ndarray(shape = (1, 9), 
                           dtype = numpy.int32)

# Contains 2 bytes - (0 to 8 -> 1 byte, 
# 9->Left most bit in second byte - remaining bits
# of second byte padded with zero to the right)
moreThanAByte[0] = [1, 0, 1, 0, 1, 0, 1, 0, 1]

# When packed row-wise one uint8 is created for each byte
ints = numpy.packbits(moreThanAByte, axis=1)
print(moreThanAByte)
print(ints)

# When packed column-wise one uint8 is created for each column
ints = numpy.packbits(moreThanAByte, axis=0)
print(ints)

Output:

[[1 0 1 0 1 0 1 0 1]]

[[170 128]]

[[128   0 128   0 128   0 128   0 128]]

Example3 - packing in little endian format:

By default the numpy.packbits() interprets the bits in big endian format(a.k.a network byte order or internet byte order). The example below creates numpy.uint8 instances in little endian format by specifying the parameter value bitorder="little".

# Example Python program that use numpy.packbits()
# to interpret the ndarray columns in little endian
# order.(Default is the big endian order).
import numpy

# Another ndarray with two bytes - this time on axis 0
x = numpy.ndarray(shape = (10, 2), 
                  dtype = numpy.int32)

# Populate the array
for i in range(0, 2):
    if i:
        prev = True
    else:
        prev = False
    for j in range(0, 10):
        if prev: 
            val = bool(0)
            x[j][i] = val
            prev = val
        else:
            val = bool(1)
            x[j][i] = val
            prev = val

print("Input array:")
print(x)

print("The uints packed column-wise in little endian format:")
littleEndians = numpy.packbits(x, axis=0, bitorder="little")
print(littleEndians)

print("Shape of the returned array:")
print(littleEndians.shape)

print("The uints packed row-wise in little endian format:")
littleEndians = numpy.packbits(x, axis=1, bitorder="little")
print(littleEndians)

print("Shape of the returned array:")
print(littleEndians.shape)

Output:

Input array:

[[1 0]

 [0 1]

 [1 0]

 [0 1]

 [1 0]

 [0 1]

 [1 0]

 [0 1]

 [1 0]

 [0 1]]

The uints packed column-wise in little endian format:

[[ 85 170]

 [  1   2]]

Shape of the returned array:

(2, 2)

The uints packed row-wise in little endian format:

[[1]

 [2]

 [1]

 [2]

 [1]

 [2]

 [1]

 [2]

 [1]

 [2]]

Shape of the returned array:

(10, 1)

 


Copyright 2024 © pythontic.com