List comprehension or map () or loop to access the previous line to manipulate the array

Let's say I have an array (numpy array) A = [[1, 2, 3], [0, 0, 0], [0, 0, 0]]

and I want to manipulate null strings in [2, 3, 1], [3, 1, 2]

, so the last array isA = [[1, 2, 3], [2, 3, 1], [3, 1, 2]]

I can do this with a for loop that looks like this:

a = np.array([[1, 2, 3],[0, 0, 0],[0, 0, 0]])
for i in xrange(1,3):
    a[i]=np.concatenate([a[i-1][1:], a[i-1][:1]], axis=1)

      

Go to the previous line, concatenate [1:] and [: 1], assign the result as the next line.

I have several of these loops and I am wondering if I can get rid of the loops to get some extra speed (maybe?). Is there a way I can do this using a list comprehension or a map? My array should not be nxn with zero strings other than the first one, it might just be A = [1, 2, 3, ..., n]

if there is a way I can create an nx3 array using A as a starter and keep taking the previous row and concatenating [m:]

and [:m]

from it. (arbitrary m)

Or yes, maybe for a loop is the only / correct way to do such an operation. I would like to know if it is.

+3


source to share


3 answers


A for-loop is the easiest way, list comprehension or map won't get much speed. But instead of concatenation, you can use roll

:



a = numpy.array([1, 2, 3])
a = numpy.vstack([numpy.roll(a, -i) for i in xrange(3)])

      

+2


source


I suggest a way to use python built-in function zip

. You can concatenate your array with yourself, then all you need is to select every three elements:

>>> A=np.arange(1,4)
>>> B=np.concatenate((A,A))
>>> B
array([1, 2, 3, 1, 2, 3])
>>> np.array(zip(B,B[1:],B[2:])[:-1])
array([[1, 2, 3],
       [2, 3, 1],
       [3, 1, 2]])

      



You can use this recipe for longer arrays:

>>> A=np.arange(1,6)
>>> B=np.concatenate((A,A))
>>> np.array(zip(B,B[1:],B[2:])[:-1])
array([[1, 2, 3],
       [2, 3, 4],
       [3, 4, 5],
       [4, 5, 1],
       [5, 1, 2],
       [1, 2, 3],
       [2, 3, 4]])
>>> 

      

+1


source


Here is a solution to avoid loops in Python. You can get the desired result by creating an array of indices, which you can use to index into the original array:

In [40]:

    a = np.arange(1, 4)
    i = np.arange(len(a))
    indexer = i - np.atleast_2d(i).T 
    a[indexer]

Out[40]:
array([[1, 2, 3],
       [3, 1, 2],
       [2, 3, 1]])

      

This will work for anyone a

. The array indexer

is the size of the desired result and is created using the broadcast. In this case, it looks like

array([[ 0,  1, 2], 
       [-1,  0, 1], 
       [-2, -1, 0]])

      

Here are some time comparisons to loop methods that show this significantly faster:

In [69]:

%%timeit 
a = np.arange(1, 11)
i = np.arange(0, len(a), step_size)
indexer = i - np.atleast_2d(i).T 
a[indexer]
10000 loops, best of 3: 14.7 ยตs per loop

In [70]:

%%timeit
a = numpy.arange(1, 11)
a = numpy.vstack([numpy.roll(a, -i) for i in xrange(len(a))])
10000 loops, best of 3: 143 ยตs per loop

In [71]:

%%timeit 
a = np.arange(1, 101)
i = np.arange(0, len(a), step_size)
indexer = i - np.atleast_2d(i).T 
a[indexer]
10000 loops, best of 3: 80 ยตs per loop

In [72]:

%%timeit
a = numpy.arange(1, 101)
a = numpy.vstack([numpy.roll(a, -i) for i in xrange(len(a))])
1000 loops, best of 3: 1.44 ms per loop

      

It also has the advantage that you can reuse indexer

to manage other arrays of the same length at the same time. If you really wanted to, you could burn it to disc. For an arbitrary step size, m

you can do the following:

In [61]:

m = 2
a = np.arange(1, 4)
i = np.arange(len(a))
indexer = (i - m * np.atleast_2d(i).T) % len(a)
a[indexer]

Out[61]:
array([[1, 2, 3],
       [2, 3, 1],
       [3, 1, 2]])

      

0


source







All Articles