Inplace changes the position of an element in an array, moving others forward - NumPy

After searching, I find no native method or current solution for effectively changing the position of an element in a numpy array, which seems to me quite natural work. For example, if I want to move the 3rd element in the 1st position, it should look like this:

x = np.array([1,2,3,4,5])
f*(x, 3, 1)

print x
array([1,4,2,3,5])

I need a f * function. This is different from collapsing each element, as well as for movements in a large array. I want to avoid the copy operation, which can be used with the insert and delete operations.

+4
source share
3 answers

, numpy, .. a[:-1]=a[1:], ( np.roll()). " ", :

40000 100

1.015ms divakar
1.078ms hpaulj
29.7micro s in place shift (34 x faster)

40000 39900

0.975ms divakar
0.985ms hpaulj
3.47micro s in place shift (290 x faster)

:

import timeit

init = '''
import numpy as np

def divakar(in_arr, pick_idx, put_idx ):    
    range_arr = np.arange(in_arr.size)  
    tmp = in_arr[pick_idx]
    in_arr[range_arr != put_idx ] = in_arr[range_arr != pick_idx]
    in_arr[put_idx] = tmp

def hpaulj(arr, fr, to):
  L = arr.shape[0]
  idx = np.concatenate((np.arange(to), [fr], np.arange(to, fr), np.arange(fr+1, L)))
  return arr[idx]

def paddyg(arr, fr, to):
  if fr >= arr.size or to >= arr.size:
    return None
  tmp = arr[fr].copy()
  if fr > to:
    arr[to+1:fr+1] = arr[to:fr]
  else:
    arr[fr:to] = arr[fr+1:to+1]
  arr[to] = tmp
  return arr

a = np.random.randint(0, 1000, (100000))
'''


fns = ['''
divakar(a, 40000, 100)
''', '''
hpaulj(a, 40000, 100)
''', '''
paddyg(a, 40000, 100)
''']

for f in fns:
  print(timeit.timeit(f, setup=init, number=1000))
+1

, masking -

def change_pos(in_arr, pick_idx, put_idx ):    
    range_arr = np.arange(in_arr.size)  
    tmp = in_arr[pick_idx]
    in_arr[range_arr != put_idx ] = in_arr[range_arr != pick_idx]
    in_arr[put_idx] = tmp

, .

1) -

In [542]: in_arr
Out[542]: array([4, 9, 3, 6, 8, 0, 2, 1])
                                   *    
In [543]: change_pos(in_arr,6,1)

In [544]: in_arr
Out[544]: array([4, 2, 9, 3, 6, 8, 0, 1])
                    ^

2) -

In [546]: in_arr
Out[546]: array([4, 9, 3, 6, 8, 0, 2, 1])
                    *
In [547]: change_pos(in_arr,1,6)

In [548]: in_arr
Out[548]: array([4, 3, 6, 8, 0, 2, 9, 1])
                                   ^
+2

, @Divakar:

def foo4(arr, i,j):
    L=arr.shape[0]
    idx=np.concatenate((np.arange(j),[i],np.arange(j,i),np.arange(i+1,L)))
    return arr[idx]

. inplace , Divakar.

def foo2(arr, i,j):
    L=arr.shape[0]
    tgt=np.arange(j,i+1)
    src=np.concatenate([[i],np.arange(j,i)])
    arr[tgt]=arr[src]

, , .

Since the data for the array is stored in a contiguous block of memory, the elements cannot be changed without any copy. You will have a list of lists as a linked list to have a form without copying.

It just occurred to me that there are some masked functions copytoand placethat could make this type of copy / move faster. But I did not work much with them.

fooobar.com/questions/1659352 / ...

=================

np.roll does

idx = np.concatenate((np.arange(2,5),np.arange(2)))
#  array([2, 3, 4, 0, 1])
np.take(a, idx)   # or a[idx]
+2
source

Source: https://habr.com/ru/post/1659350/


All Articles