Skip to content Skip to sidebar Skip to footer

Create A Matrix From A Vector Where Each Row Is A Shifted Version Of The Vector

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: array([[4, 1, 2, 3], [3, 4, 1, 2],

Solution 1:

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 -

defstrided_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

Solution 2:

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]])

Solution 3:

Here's one approach

defroll_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

Post a Comment for "Create A Matrix From A Vector Where Each Row Is A Shifted Version Of The Vector"