Create a matrix from a vector where each row is a shifted version of the vector

后端 未结 3 684
栀梦
栀梦 2020-12-19 06:49

I have a numpy array like this

import numpy as np

ar = np.array([1, 2, 3, 4])

and I want to create an array that looks like this:

相关标签:
3条回答
  • 2020-12-19 07:13

    Both of the existing answers are fine; this answer is probably only of interest if you are already using scipy.

    The matrix that you describe is known as a circulant matrix. If you don't mind the dependency on scipy, you can use scipy.linalg.circulant to create one:

    In [136]: from scipy.linalg import circulant
    
    In [137]: ar = np.array([1, 2, 3, 4])
    
    In [138]: circulant(ar[::-1])
    Out[138]: 
    array([[4, 1, 2, 3],
           [3, 4, 1, 2],
           [2, 3, 4, 1],
           [1, 2, 3, 4]])
    
    0 讨论(0)
  • 2020-12-19 07:15

    Here's one approach using NumPy strides basically padding with the leftover elements and then the strides helping us in creating that shifted version pretty efficiently -

    def strided_method(ar):
        a = np.concatenate(( ar, ar[:-1] ))
        L = len(ar)
        n = a.strides[0]
        return np.lib.stride_tricks.as_strided(a[L-1:], (L,L), (-n,n))
    

    Sample runs -

    In [42]: ar = np.array([1, 2, 3, 4])
    
    In [43]: strided_method(ar)
    Out[43]: 
    array([[4, 1, 2, 3],
           [3, 4, 1, 2],
           [2, 3, 4, 1],
           [1, 2, 3, 4]])
    
    In [44]: ar = np.array([4,9,3,6,1,2])
    
    In [45]: strided_method(ar)
    Out[45]: 
    array([[2, 4, 9, 3, 6, 1],
           [1, 2, 4, 9, 3, 6],
           [6, 1, 2, 4, 9, 3],
           [3, 6, 1, 2, 4, 9],
           [9, 3, 6, 1, 2, 4],
           [4, 9, 3, 6, 1, 2]])
    

    Runtime test -

    In [5]: a = np.random.randint(0,9,(1000))
    
    # @Eric's soln
    In [6]: %timeit roll_matrix(a)
    100 loops, best of 3: 3.39 ms per loop
    
    # @Warren Weckesser's soln
    In [8]: %timeit circulant(a[::-1])
    100 loops, best of 3: 2.03 ms per loop
    
    # Strides method
    In [18]: %timeit strided_method(a)
    100000 loops, best of 3: 6.7 µs per loop
    

    Making a copy (if you want to make changes and not just use as a read only array) won't hurt us too badly for the strides method -

    In [19]: %timeit strided_method(a).copy()
    1000 loops, best of 3: 381 µs per loop
    
    0 讨论(0)
  • 2020-12-19 07:15

    Here's one approach

    def roll_matrix(vec):
        N = len(vec)
        buffer = np.empty((N, N*2 - 1))
    
        # generate a wider array that we want a slice into
        buffer[:,:N] = vec
        buffer[:,N:] = vec[:-1]
    
        rolled = buffer.reshape(-1)[N-1:-1].reshape(N, -1)
        return rolled[:,:N]
    

    In your case, we build buffer to be

    array([[ 1.,  2.,  3.,  4.,  1.,  2.,  3.],
           [ 1.,  2.,  3.,  4.,  1.,  2.,  3.],
           [ 1.,  2.,  3.,  4.,  1.,  2.,  3.],
           [ 1.,  2.,  3.,  4.,  1.,  2.,  3.]])
    

    Then flatten it, trim it, reshape it to get rolled:

    array([[ 4.,  1.,  2.,  3.,  1.,  2.],
           [ 3.,  4.,  1.,  2.,  3.,  1.],
           [ 2.,  3.,  4.,  1.,  2.,  3.],
           [ 1.,  2.,  3.,  4.,  1.,  2.]])
    

    And finally, slice off the garbage last columns

    0 讨论(0)
提交回复
热议问题