Search code examples
pythonarraysnumpypad

python how to pad numpy array with zeros


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

Solution

  • 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)