2010-05-06 127 views
29

我想在Python中滚动2D numpy,除了我想用零填充两端而不是滚动数据,就好像它的周期一样。python numpy roll with padding

具体来说,以下代码

import numpy as np 

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

np.roll(x, 1, axis=1) 

回报

array([[3, 1, 2],[6, 4, 5]]) 

但我宁愿是

array([[0, 1, 2], [0, 4, 5]]) 

我可以用几个尴尬touchups做到这一点,但我希望有一种方法可以用快速的内置命令来实现。

感谢

回答

24

有版本1.7.0 numpy.pad新numpy的功能可以为此在一行。 Pad似乎相当强大,并且可以做的不仅仅是一个简单的“滚动”。此答案中使用的元组((0,0),(1,0))指示要填充的矩阵的“边”。

import numpy as np 
x = np.array([[1, 2, 3],[4, 5, 6]]) 

print np.pad(x,((0,0),(1,0)), mode='constant')[:, :-1] 

给予

[[0 1 2] 
[0 4 5]] 
+2

如果不是很明显,这里是移动5个元素:print np.pad(x,((0,0),(5,0)),mode ='constant')[:,:-5] – 2014-03-28 22:35:48

+0

哇,很棒的发现一个4岁的职位! – 2014-04-15 01:37:30

14

我不认为你会找到一个更简单的方式来做到这一点,是内置。触摸起来似乎很简单,对我说:

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

如果你希望这是更直接的,那么也许你可以在滚动功能复制到一个新的功能,改变它做你想要的。 roll()函数位于site-packages\core\numeric.py文件中。

+1

我希望这样做在一条线中,由于我需要这种多次做在不同的方向,我不能打嗝,但你的建议可能是最好的解决方案。谢谢你的帮助。 – 2010-05-06 02:47:57

4

我刚刚写了以下内容。可以通过避免zeros_like和直接计算zeros的形状来进一步优化。

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

谢谢,它看起来可能是有用的。然而,根据cPro​​file的说法,我在玩弄你的建议,并且它似乎比Justin最初的建议慢两倍(随机(1e4 x 1e4)阵列为1.8秒vs 0.8秒)。它看起来像连接调用正在导致双重执行时间。 – 2010-07-05 02:11:37

0

你也可以使用numpy的triu和scipy.linalg的循环。制作一个循环版本的矩阵。然后,选择从第一个对角线开始的上三角形部分(Triu中的默认选项)。行索引将对应于您想要填充的零的数量。

如果您没有scipy,您可以通过制作(n-1)X(n-1)单位矩阵并在其上堆叠一行[0 0 ... 1]来生成nXn循环矩阵和它右侧的列[1 0 ... 0]。

2

有点晚了,但感觉就像是一种快速的方式来做你想要的一行。也许会工作最好的,如果包裹智能函数内(例如低于只是为横轴提供):

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

请注意:由于'a [:,: - shift]'这不适用于'shift = 0'。如果将换档过程置于一般功能中,这可能很重要。 – EOL 2014-06-08 09:03:01

1
import numpy as np 

def shift_2d_replace(data, dx, dy, constant=False): 
    """ 
    Shifts the array in two dimensions while setting rolled values to constant 
    :param data: The 2d numpy array to be shifted 
    :param dx: The shift in x 
    :param dy: The shift in y 
    :param constant: The constant to replace rolled values with 
    :return: The shifted array with "constant" where roll occurs 
    """ 
    shifted_data = np.roll(data, dx, axis=1) 
    if dx < 0: 
     shifted_data[:, dx:] = constant 
    elif dx > 0: 
     shifted_data[:, 0:np.abs(dx)] = constant 

    shifted_data = np.roll(shifted_data, dy, axis=0) 
    if dy < 0: 
     shifted_data[dy:, :] = constant 
    elif dy > 0: 
     shifted_data[0:np.abs(dy), :] = constant 
    return shifted_data 

此功能对二维数组会工作,并与您所选择的常数代替冷轧值。

0

由迷上了答案阐述(因为我花了几分钟的时间去了解它)

低于第一片的代码在了一定量的零,下,左,右页边距,然后选择原始矩阵内填充一个。一个完美无用的代码,但很好理解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) 

现在作出的2的1个位置的向右移位组合的一个向上移位一个应该做

print np.pad(x,((0,2),(1,0)), mode='constant')[2:0,0:-1]