I want to know how I can pad a 2D numpy array with zeros using python 2.6.6 with numpy version 1.5.0. But these are my limitations. Therefore I cannot use np.pad
. For example, I want to pad a
with zeros such that its shape matches b
. The reason why I want to do this is so I can do:
b-a
such that
>>> a array([[ 1., 1., 1., 1., 1.], [ 1., 1., 1., 1., 1.], [ 1., 1., 1., 1., 1.]]) >>> b array([[ 3., 3., 3., 3., 3., 3.], [ 3., 3., 3., 3., 3., 3.], [ 3., 3., 3., 3., 3., 3.], [ 3., 3., 3., 3., 3., 3.]]) >>> c array([[1, 1, 1, 1, 1, 0], [1, 1, 1, 1, 1, 0], [1, 1, 1, 1, 1, 0], [0, 0, 0, 0, 0, 0]])
The only way I can think of doing this is appending, however this seems pretty ugly. is there a cleaner solution possibly using b.shape
?
Edit, Thank you to MSeiferts answer. I had to clean it up a bit, and this is what I got:
def pad(array, reference_shape, offsets): """ array: Array to be padded reference_shape: tuple of size of ndarray to create offsets: list of offsets (number of elements must be equal to the dimension of the array) will throw a ValueError if offsets is too big and the reference_shape cannot handle the offsets """ # Create an array of zeros with the reference shape result = np.zeros(reference_shape) # Create a list of slices from offset to offset + shape in each dimension insertHere = [slice(offsets[dim], offsets[dim] + array.shape[dim]) for dim in range(array.ndim)] # Insert the array in the result at the specified offsets result[insertHere] = array return result
Advertisement
Answer
Very simple, you create an array containing zeros using the reference shape:
result = np.zeros(b.shape) # actually you can also use result = np.zeros_like(b) # but that also copies the dtype not only the shape
and then insert the array where you need it:
result[:a.shape[0],:a.shape[1]] = a
and voila you have padded it:
print(result) array([[ 1., 1., 1., 1., 1., 0.], [ 1., 1., 1., 1., 1., 0.], [ 1., 1., 1., 1., 1., 0.], [ 0., 0., 0., 0., 0., 0.]])
You can also make it a bit more general if you define where your upper left element should be inserted
result = np.zeros_like(b) x_offset = 1 # 0 would be what you wanted y_offset = 1 # 0 in your case result[x_offset:a.shape[0]+x_offset,y_offset:a.shape[1]+y_offset] = a result array([[ 0., 0., 0., 0., 0., 0.], [ 0., 1., 1., 1., 1., 1.], [ 0., 1., 1., 1., 1., 1.], [ 0., 1., 1., 1., 1., 1.]])
but then be careful that you don’t have offsets bigger than allowed. For x_offset = 2
for example this will fail.
If you have an arbitary number of dimensions you can define a list of slices to insert the original array. I’ve found it interesting to play around a bit and created a padding function that can pad (with offset) an arbitary shaped array as long as the array and reference have the same number of dimensions and the offsets are not too big.
def pad(array, reference, offsets): """ array: Array to be padded reference: Reference array with the desired shape offsets: list of offsets (number of elements must be equal to the dimension of the array) """ # Create an array of zeros with the reference shape result = np.zeros(reference.shape) # Create a list of slices from offset to offset + shape in each dimension insertHere = [slice(offset[dim], offset[dim] + array.shape[dim]) for dim in range(a.ndim)] # Insert the array in the result at the specified offsets result[insertHere] = a return result
And some test cases:
import numpy as np # 1 Dimension a = np.ones(2) b = np.ones(5) offset = [3] pad(a, b, offset) # 3 Dimensions a = np.ones((3,3,3)) b = np.ones((5,4,3)) offset = [1,0,0] pad(a, b, offset)