简体   繁体   中英

Create a “wrapped” ndarray from a given array

I'm trying to create a 2D array from an array by using a rolled given array as the rows of the 2D array of a specified row dimension. For example:

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

want a matrix of 3 rows (using r) as

[[2,3,4,1],
 [1,2,3,4],
 [4,1,2,3]]

I think I have an idea by defining a function using numpy.roll and a for-loop but I'm trying to avoid that as my 2D array is going to be very large. I would like to have the ability to roll backwards if possible.

Is there a way using numpy functions that can do this instead? Any suggestions on this are appreciated.

If using scipy is an option, you can use scipy.linalg.circulant . You will still have to tweak the argument to circulant to get exactly what you want, since circulant simply makes the given one-dimensional argument the first column of a square circulant matrix .

For example:

In [25]: from scipy.linalg import circulant

In [26]: r = np.array([1,2,3,4])

Here's what circulant gives:

In [27]: circulant(r)
Out[27]: 
array([[1, 4, 3, 2],
       [2, 1, 4, 3],
       [3, 2, 1, 4],
       [4, 3, 2, 1]])

With some help from np.roll() , you can get your desired array:

In [28]: circulant(np.roll(r, -1)).T[:-1]
Out[28]: 
array([[2, 3, 4, 1],
       [1, 2, 3, 4],
       [4, 1, 2, 3]])

Or:

In [29]: circulant(np.roll(r[::-1], -1))[1:]
Out[29]: 
array([[2, 3, 4, 1],
       [1, 2, 3, 4],
       [4, 1, 2, 3]])

This is a solution to the problem. It uses numpy's vstack to combine the rows into an array. It is maybe not the most efficient one though (I don't know the efficiency of res = np.vstack((res, r)) )

import numpy as np

def main():
    r = np.array([1,2,3,4])
    x = [i for i in range(1, len(r))] + [0]           # Forwards
    # x = [len(r)-1] + [i for i in range(len(r)-1)]     # Backwards
    r = r[x]
    res = r
    for c in range(2):
        r = r[x]
        res = np.vstack((res, r))
    print res
    return 0

if __name__ == '__main__':
    main()

It produces:

[[2 3 4 1]     'Forwards'
 [3 4 1 2]
 [4 1 2 3]]

[[4 1 2 3]     'Backwards'
 [3 4 1 2]
 [2 3 4 1]]

To change the order, it's only necessary to change the x = line.

Here's a simple solution using list indexing.

r = [1, 2, 3, 4] # note: a list, so we can easily concatenate
result = np.array([r[i:] + r[:i] for i in range(1, len(r))])

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

This is pretty flexible because the indexing is still meaningful for negative values of i . So you just have to mess around with range to get the desired start and stop rows, and direction.

In particular, to get the exact result you wanted:

np.array([r[i:] + r[:i] for i in range(1, -len(r) + 2, -1)])

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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM