矩阵:有效地将第n行移动n个位置



我有一个numpy 2d数组,我需要对它进行转换,使第一行保持不变,第二行向右移动一个位置(它可以换行,也可以只在前面填充零(。第三排向右移动3个位置等。我可以通过"for循环"来实现,但这不是很有效。我猜应该有一个过滤矩阵,乘以原始矩阵会有同样的效果,或者可能有一个愚蠢的技巧可以帮助我做到这一点?谢谢我已经研究过numpy.roll((,但我不认为它可以分别处理每一行。

import numpy as np
p = np.array([[1,2,3,4],[5,6,7,8],[9,10,11,12],[13,14,15,16]])
'''
p = [ 1   2   3   4
5   6   7   8
9   10  11  12
13  14  15  16]
desired output:
p'= [ 1   2   3   4
0   5   6   7
0   0   9   10
0   0   0   13]
'''

我们可以将滑动窗口提取到输入的零填充版本中,以获得高效的内存方法,从而提高性能。为了获得这些窗口,我们可以利用基于np.lib.stride_tricks.as_stridedscikit-image's view_as_windows。有关使用基于as_stridedview_as_windows的更多信息。

因此,解决方案将是-

from skimage.util.shape import view_as_windows
def slide_by_one(p):
m,n = p.shape
z = np.zeros((m,m-1),dtype=p.dtype)
a = np.concatenate((z,p),axis=1)
w  = view_as_windows(a,(1,p.shape[1]))[...,0,:]
r = np.arange(m)
return w[r,r[::-1]]

样品运行-

In [60]: p # generic sample of size mxn
Out[60]: 
array([[ 1,  5,  9, 13, 17],
[ 2,  6, 10, 14, 18],
[ 3,  7, 11, 15, 19],
[ 4,  8, 12, 16, 20]])
In [61]: slide_by_one(p)
Out[61]: 
array([[ 1,  5,  9, 13, 17],
[ 0,  2,  6, 10, 14],
[ 0,  0,  3,  7, 11],
[ 0,  0,  0,  4,  8]])

我们可以利用常规的rampy模式,通过更原始地使用np.lib.stride_tricks.as_strided来获得更有效的方法,比如so-

def slide_by_one_v2(p):
m,n = p.shape
z = np.zeros((m,m-1),dtype=p.dtype)
a = np.concatenate((z,p),axis=1)
s0,s1 = a.strides
return np.lib.stride_tricks.as_strided(a[:,m-1:],shape=(m,n),strides=(s0-s1,s1))

另一个带有masking-的

def slide_by_one_v3(p):
m,n = p.shape
z = np.zeros((len(p),1),dtype=p.dtype)
a = np.concatenate((p,z),axis=1)
return np.triu(a[:,::-1],1)[:,::-1].flat[:-m].reshape(m,-1)

这里有一个基于零填充和整形的简单方法。它很快,因为它避免了高级索引和其他开销。

def pp(p):
m,n = p.shape
aux = np.zeros((m,n+m-1),p.dtype)
np.copyto(aux[:,:n],p)
return aux.ravel()[:-m].reshape(m,n+m-2)[:,:n].copy()

最新更新