77

What's the more pythonic way to pad an array with zeros at the end?

def pad(A, length):
    ...

A = np.array([1,2,3,4,5])
pad(A, 8)    # expected : [1,2,3,4,5,0,0,0]

In my real use case, in fact I want to pad an array to the closest multiple of 1024. Ex: 1342 => 2048, 3000 => 3072

8 Answers 8

126

numpy.pad with constant mode does what you need, where we can pass a tuple as second argument to tell how many zeros to pad on each size, a (2, 3) for instance will pad 2 zeros on the left side and 3 zeros on the right side:

Given A as:

A = np.array([1,2,3,4,5])

np.pad(A, (2, 3), 'constant')
# array([0, 0, 1, 2, 3, 4, 5, 0, 0, 0])

It's also possible to pad a 2D numpy arrays by passing a tuple of tuples as padding width, which takes the format of ((top, bottom), (left, right)):

A = np.array([[1,2],[3,4]])

np.pad(A, ((1,2),(2,1)), 'constant')

#array([[0, 0, 0, 0, 0],           # 1 zero padded to the top
#       [0, 0, 1, 2, 0],           # 2 zeros padded to the bottom
#       [0, 0, 3, 4, 0],           # 2 zeros padded to the left
#       [0, 0, 0, 0, 0],           # 1 zero padded to the right
#       [0, 0, 0, 0, 0]])

For your case, you specify the left side to be zero and right side pad calculated from a modular division:

B = np.pad(A, (0, 1024 - len(A)%1024), 'constant')
B
# array([1, 2, 3, ..., 0, 0, 0])
len(B)
# 1024

For a larger A:

A = np.ones(3000)
B = np.pad(A, (0, 1024 - len(A)%1024), 'constant')
B
# array([ 1.,  1.,  1., ...,  0.,  0.,  0.])

len(B)
# 3072
Sign up to request clarification or add additional context in comments.

6 Comments

Thanks! Does it work if original length is 3000 ? (then padded length should be 3072)
It should, since the right padding length here is the difference between 1024 and the modular remainder of len(A) divided by 1024. It should be easy to test.
what if I have a 3d volume to pad?
This is really the clearest example I'd ever seen. Thank you!!
mode='constant' is the default value, no need to specify it directly. Docs: numpy.org/doc/stable/reference/generated/numpy.pad.html
|
19

For your use case you can use resize() method:

A = np.array([1,2,3,4,5])
A.resize(8)

This resizes A in place. If there are refs to A numpy throws a vale error because the referenced value would be updated too. To allow this add refcheck=False option.

The documentation states that missing values will be 0:

Enlarging an array: as above, but missing entries are filled with zeros

Comments

14

For future reference:

def zeropad(A, size):
    t = size - len(A)
    return np.pad(A, pad_width=(0, t), mode='constant')

zeropad([1,2,3], 8)     # [1 2 3 0 0 0 0 0]

Note: For a n-dimensional version, here it is, see Zero pad a numpy n-dimensional array:

def zeropad(arr, shape):
    return np.pad(arr, [(0, max(s - dim, 0)) for s, dim in zip(shape, arr.shape)], mode='constant', constant_values=0)

Comments

8

You could also use numpy.pad:

>>> A = np.array([1,2,3,4,5])
>>> npad = 8 - len(A)
>>> np.pad(A, pad_width=npad, mode='constant', constant_values=0)[npad:]
array([1, 2, 3, 4, 5, 0, 0, 0])

And in a function:

def pad(A, npads):
    _npads = npads - len(A)
    return np.pad(A, pad_width=_npads, mode='constant', constant_values=0)[_npads:]

Comments

7

There's np.pad:

A = np.array([1, 2, 3, 4, 5])
A = np.pad(A, (0, length), mode='constant')

Regarding your use case, the required number of zeros to pad can be calculated as length = len(A) + 1024 - 1024 % len(A).

Comments

7

This should work:

def pad(A, length):
    arr = np.zeros(length)
    arr[:len(A)] = A
    return arr

You might be able to get slightly better performance if you initialize an empty array (np.empty(length)) and then fill in A and the zeros separately, but I doubt that the speedups would be worth additional code complexity in most cases.

To get the value to pad up to, I think you'd probably just use something like divmod:

n, remainder = divmod(len(A), 1024)
n += bool(remainder)

Basically, this just figures out how many times 1024 divides the length of your array (and what the remainder of that division is). If there is no remainder, then you just want n * 1024 elements. If there is a remainder, then you want (n + 1) * 1024.

all-together:

def pad1024(A):
    n, remainder = divmod(len(A), 1024)
    n += bool(remainder)
    arr = np.zeros(n * 1024)
    arr[:len(A)] = A
    return arr        

3 Comments

Thanks! Any idea for automatic padding to make the length a multiple of 1024 ? I'm writing something but it's highly non pythonic ;)
@Basj -- Sure, check my update. I didn't test it or anything, but I think it should work...
This is what pad does but with a lot bells-n-whistles (front, back, different axes, other fill modes).
1

If the desired length should be the closest multiple of 1024, then you can try bit shift operations << and >> like below.

For example, given A = np.array([1,2,3,4,5]), you can run

(B:=np.zeros((((A.size>>10)+1)<<10))).put(np.arange(A.size), A)

or

(B:=A.copy()).resize((((A.size>>10)+1)<<10))

and check the resulting B

print(f'B is:\n{B}\n')
print(f'size of B is:\n {B.size}\n')

such that

B is:
[1. 2. 3. ... 0. 0. 0.]

size of B is:
 1024

Comments

1
import numpy as np

def pad_to_multiple(a, multiple):
    length = len(a)
    target = ((length + multiple - 1) // multiple) * multiple  # round up
    return np.pad(a, (0, target - length), mode='constant')

A = np.array([1, 2, 3, 4, 5])
print(pad_to_multiple(A, 8))      # [1 2 3 4 5 0 0 0]
print(pad_to_multiple(A, 1024))   # length will be 1024
print(pad_to_multiple(np.arange(1342), 1024).size)  # 2048
print(pad_to_multiple(np.arange(3000), 1024).size)  # 3072

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.