在Python/numpy中环绕切片

Nat*_*iel 23 python numpy

我有一个numpy数组,我想获得第i点的"邻域".通常我使用的数组是二维的,但下面的一维示例说明了我正在寻找的内容.如果

A = numpy.array([0,10,20,30,40,50,60,70,80,90])
Run Code Online (Sandbox Code Playgroud)

然后,元素4的(大小5)邻域是[20,30,40,50,60],并且这可以通过这样做容易地获得A[i-2:i+3].

但是,我还需要邻域"环绕"数组的边缘,以便元素0 [80,90,0,10,20]的邻域是和元素9的邻域[70,80,90,0,10].我似乎无法找到一种优雅的方法来做到这一点,所以每次出现时我都不得不使用一些复杂,烦人的逻辑(这对我来说很常见).在2D情况下,点的邻域将是矩形阵列.

所以我的问题是,是否有一种巧妙的方式来表达这个"环绕邻居"操作在numpy?我更喜欢返回切片而不是副本的东西,但可读性和速度是最重要的考虑因素.

Hen*_*rik 27

numpy.take'wrap'模式下将使用您的索引模数组的长度.

indices = range(i-2,i+3)
neighbourhood = A.take(indices, mode='wrap')
Run Code Online (Sandbox Code Playgroud)

请参阅文档了解详细信 numpy.take

  • 打败我10秒钟.Hmmph!请注意,您还可以将`take`作为数组方法访问,即`A.take(indices,mode ='wrap')`. (4认同)

tai*_*raj 5

您可以使用参数axis=0numpy.take为第二阵列.

A = zip(range(0,101,10),range(0,11)) #create 2-d list
A = numpy.array(A)   #create 2-d array  
indices = range(i-2,i+3)
neightbourhood = A.take(indices,axis=0,mode='wrap')
Run Code Online (Sandbox Code Playgroud)

同样axis=0适用于n*m尺寸......


Nea*_*uis 5

注意:对于邻居不需要包装的情况,numpy.take比简单地切片要慢A[i-2:i+3]。你可能想用一些条件语句来包装你的邻居函数:

def neighbors(a,i,n):
    N = a.shape[0] 
    if i - n < 0 and i + n > 0:
        indices = range(i-n,i+n+1)
        nbrs = a.take(indices, mode='wrap')
    elif i-n < N - 1 and i+n > N - 1:
        indices = range(i-n,i+n+1)
        nbrs = a.take(indices, mode='wrap')
    else:
        nbrs = a[i-n:i+n+1]
    return nbrs
Run Code Online (Sandbox Code Playgroud)

如果您发现自己在遍历数组时使用邻居,例如在居中移动平均线中,您会发现这需要更少的时间,尤其是对于较长的数组:

在此处输入图片说明

这是我使用的移动平均函数:

def moving_average(a,n=1):
    N = a.shape[0] 
    ma = np.empty(N)
    for i in range(N):
        if n*2+1 > N:
            ma[i] = a.mean()
        else: 
            ma[i] = neighbors(a,i,n).mean()
    return ma
Run Code Online (Sandbox Code Playgroud)

我相信这些功能可以进一步改进。我愿意接受建议。