Numpy -1D输入数组的多个numpy.卷

mwg9r5ms  于 2023-04-21  发布在  其他
关注(0)|答案(3)|浏览(133)

我想返回一个2D numpy.array,其中包含多卷给定的1D numpy.array

>>> multiroll(np.arange(10), [-1, 0, 1, 2])
array([[1., 0., 9., 8.],
       [2., 1., 0., 9.],
       [3., 2., 1., 0.],
       [4., 3., 2., 1.],
       [5., 4., 3., 2.],
       [6., 5., 4., 3.],
       [7., 6., 5., 4.],
       [8., 7., 6., 5.],
       [9., 8., 7., 6.],
       [0., 9., 8., 7.]])

是否有numpy.rollnumpy.tilenumpy.repeat或其他函数的组合可以实现此功能?

这就是我所尝试的

def multiroll(array, rolls):
    """Create multiple rolls of 1D vector"""
    m = len(array)
    n = len(rolls)
    shape = (m, n)
    a = np.empty(shape)
    for i, roll in enumerate(rolls):
        a[:,i] = np.roll(array, roll)
    return a

我希望有一个更“Numpythonic”的方式来做这件事,不使用循环。

wfsdck30

wfsdck301#

**方法#1:为了优雅

这里有一种处理broadcasting的方法-

In [44]: a
Out[44]: array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])

In [45]: rolls
Out[45]: array([-1,  0,  1,  2])

In [46]: a[(np.arange(len(a))[:,None]-rolls) % len(a)]
Out[46]: 
array([[1, 0, 9, 8],
       [2, 1, 0, 9],
       [3, 2, 1, 0],
       [4, 3, 2, 1],
       [5, 4, 3, 2],
       [6, 5, 4, 3],
       [7, 6, 5, 4],
       [8, 7, 6, 5],
       [9, 8, 7, 6],
       [0, 9, 8, 7]])

方法#2:内存/性能效率

主要是借用了-this post的想法。
我们可以利用基于scikit-image's view_as_windowsnp.lib.stride_tricks.as_strided来获得滑动窗口. More info on use of as_strided based view_as_windows

from skimage.util.shape import view_as_windows

def multiroll_stridedview(a, r):
    r = np.asarray(r)

    # Concatenate with sliced to cover all rolls
    a_ext = np.concatenate((a,a[:-1]))

    # Get sliding windows; use advanced-indexing to select appropriate ones
    n = len(a)
    return view_as_windows(a_ext,n)[:,(n-r)%n]
kmb7vmvb

kmb7vmvb2#

方法#3:为了数学之美(和效率?)

在频域中使用fft核可以一次处理整个矩阵。这种方法只适用于整数

A = np.array([[1., 1., 1., 1.],
       [2., 2., 2., 2.],
       [3., 3., 3., 3.],
       [4., 4., 4., 4.],
       [5., 5., 5., 5.],
       [6., 6., 6., 6.],
       [7., 7., 7., 7.],
       [8., 8., 8., 8.],
       [9., 9., 9., 9.],
       [0., 0., 0., 0.]]).transpose()

m,n = A.shape
#shift vector
s=[-1,0,1,2] 
#transformation kernel (shift theorem)
fftkernel = np.exp(-2*1j*np.pi/n*np.outer(v,np.arange(0,n)))
#Apply the shift
res=np.round(np.fft.ifft(np.fft.fft(A,axis = 1) * fftkernel ,axis = 1)).real.transpose()

我们得到:

array([[1., 0., 9., 8.],
       [2., 1., 0., 9.],
       [3., 2., 1., 0.],
       [4., 3., 2., 1.],
       [5., 4., 3., 2.],
       [6., 5., 4., 3.],
       [7., 6., 5., 4.],
       [8., 7., 6., 5.],
       [9., 8., 7., 6.],
       [0., 9., 8., 7.]])

您可以在此处获得有关此代码如何工作的更多信息
对于左循环移位,您可以用途:

fftkernel = np.exp(2*1j*np.pi/n*np.outer(v,np.arange(0,n)))

没有负号。

zsohkypk

zsohkypk3#

另一种方法based on this answer

arr = np.tile(vec, (len(vec),1))
output = list(map(np.roll, np.squeeze(arr, 0), rolls))

相关问题