python numpy roll with padding

后端 未结 7 1010
孤街浪徒
孤街浪徒 2020-12-16 09:17

I\'d like to roll a 2D numpy in python, except that I\'d like pad the ends with zeros rather than roll the data as if its periodic.

Specifically, the following code<

相关标签:
7条回答
  • 2020-12-16 09:43

    You could also use numpy's triu and scipy.linalg's circulant. Make a circulant version of your matrix. Then, select the upper triangular part starting at the first diagonal, (the default option in triu). The row index will correspond to the number of padded zeros you want.

    If you don't have scipy you can generate a nXn circulant matrix by making an (n-1) X (n-1) identity matrix and stacking a row [0 0 ... 1] on top of it and the column [1 0 ... 0] to the right of it.

    0 讨论(0)
  • 2020-12-16 09:48

    Elaborating on the answer by Hooked (since it took me a few minutes to understand it)

    The code below first pads a certain amount of zeros in the up, down, left and right margins and then selects the original matrix inside the padded one. A perfectly useless code, but good for understanding np.pad.

    import numpy as np
    x = np.array([[1, 2, 3],[4, 5, 6]])
    y = np.pad(x,((1,3),(2,4)), mode='constant')[1:-3,2:-4]
    
    print np.all(x==y)
    

    now to make an upwards shift of 2 combined with a rightwards shift of 1 position one should do

    print np.pad(x,((0,2),(1,0)), mode='constant')[2:0,0:-1]
    
    0 讨论(0)
  • 2020-12-16 09:49

    I just wrote the following. It could be more optimized by avoiding zeros_like and just computing the shape for zeros directly.

    import numpy as np
    def roll_zeropad(a, shift, axis=None):
        """
        Roll array elements along a given axis.
    
        Elements off the end of the array are treated as zeros.
    
        Parameters
        ----------
        a : array_like
            Input array.
        shift : int
            The number of places by which elements are shifted.
        axis : int, optional
            The axis along which elements are shifted.  By default, the array
            is flattened before shifting, after which the original
            shape is restored.
    
        Returns
        -------
        res : ndarray
            Output array, with the same shape as `a`.
    
        See Also
        --------
        roll     : Elements that roll off one end come back on the other.
        rollaxis : Roll the specified axis backwards, until it lies in a
                   given position.
    
        Examples
        --------
        >>> x = np.arange(10)
        >>> roll_zeropad(x, 2)
        array([0, 0, 0, 1, 2, 3, 4, 5, 6, 7])
        >>> roll_zeropad(x, -2)
        array([2, 3, 4, 5, 6, 7, 8, 9, 0, 0])
    
        >>> x2 = np.reshape(x, (2,5))
        >>> x2
        array([[0, 1, 2, 3, 4],
               [5, 6, 7, 8, 9]])
        >>> roll_zeropad(x2, 1)
        array([[0, 0, 1, 2, 3],
               [4, 5, 6, 7, 8]])
        >>> roll_zeropad(x2, -2)
        array([[2, 3, 4, 5, 6],
               [7, 8, 9, 0, 0]])
        >>> roll_zeropad(x2, 1, axis=0)
        array([[0, 0, 0, 0, 0],
               [0, 1, 2, 3, 4]])
        >>> roll_zeropad(x2, -1, axis=0)
        array([[5, 6, 7, 8, 9],
               [0, 0, 0, 0, 0]])
        >>> roll_zeropad(x2, 1, axis=1)
        array([[0, 0, 1, 2, 3],
               [0, 5, 6, 7, 8]])
        >>> roll_zeropad(x2, -2, axis=1)
        array([[2, 3, 4, 0, 0],
               [7, 8, 9, 0, 0]])
    
        >>> roll_zeropad(x2, 50)
        array([[0, 0, 0, 0, 0],
               [0, 0, 0, 0, 0]])
        >>> roll_zeropad(x2, -50)
        array([[0, 0, 0, 0, 0],
               [0, 0, 0, 0, 0]])
        >>> roll_zeropad(x2, 0)
        array([[0, 1, 2, 3, 4],
               [5, 6, 7, 8, 9]])
    
        """
        a = np.asanyarray(a)
        if shift == 0: return a
        if axis is None:
            n = a.size
            reshape = True
        else:
            n = a.shape[axis]
            reshape = False
        if np.abs(shift) > n:
            res = np.zeros_like(a)
        elif shift < 0:
            shift += n
            zeros = np.zeros_like(a.take(np.arange(n-shift), axis))
            res = np.concatenate((a.take(np.arange(n-shift,n), axis), zeros), axis)
        else:
            zeros = np.zeros_like(a.take(np.arange(n-shift,n), axis))
            res = np.concatenate((zeros, a.take(np.arange(n-shift), axis)), axis)
        if reshape:
            return res.reshape(a.shape)
        else:
            return res
    
    0 讨论(0)
  • 2020-12-16 09:53

    There is a new numpy function in version 1.7.0 numpy.pad that can do this in one-line. Pad seems to be quite powerful and can do much more than a simple "roll". The tuple ((0,0),(1,0)) used in this answer indicates the "side" of the matrix which to pad.

    import numpy as np
    x = np.array([[1, 2, 3],[4, 5, 6]])
    
    print np.pad(x,((0,0),(1,0)), mode='constant')[:, :-1]
    

    Giving

    [[0 1 2]
     [0 4 5]]
    
    0 讨论(0)
  • 2020-12-16 09:53

    I don't think that you are going to find an easier way to do this that is built-in. The touch-up seems quite simple to me:

    y = np.roll(x,1,axis=1)
    y[:,0] = 0
    

    If you want this to be more direct then maybe you could copy the roll function to a new function and change it to do what you want. The roll() function is in the site-packages\core\numeric.py file.

    0 讨论(0)
  • 2020-12-16 10:02

    A bit late, but feels like a quick way to do what you want in one line. Perhaps would work best if wrapped inside a smart function (example below provided just for horizontal axis):

    import numpy
    
    a = numpy.arange(1,10).reshape(3,3)  # an example 2D array
    
    print a
    
    [[1 2 3]
     [4 5 6]
     [7 8 9]]
    
    shift = 1
    a = numpy.hstack((numpy.zeros((a.shape[0], shift)), a[:,:-shift]))
    
    print a
    
    [[0 1 2]
     [0 4 5]
     [0 7 8]]
    
    0 讨论(0)
提交回复
热议问题