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],
[2, 3, 4, 1],
[1, 2, 3, 4]])
Thereby, each row corresponds to ar
which is shifted by the row index + 1.
A straightforward implementation could look like this:
ar_roll = np.tile(ar, ar.shape[0]).reshape(ar.shape[0], ar.shape[0])
for indi, ri in enumerate(ar_roll):
ar_roll[indi, :] = np.roll(ri, indi + 1)
which gives me the desired output.
My question is whether there is a smarter way of doing this which avoids the loop.
Here's one approach using
NumPy strides
basically padding with the leftover elements and then thestrides
helping us in creating that shifted version pretty efficiently -Sample runs -
Runtime test -
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 -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:Here's one approach
In your case, we build
buffer
to beThen flatten it, trim it, reshape it to get
rolled
:And finally, slice off the garbage last rows