Indexing a 2D array without writing and without clipping

I have an array of indices

a = np.array([
   [0, 0],
   [1, 1],
   [1, 9]
])

And a 2D array

b = np.array([
   [0, 1, 2, 3],
   [5, 6, 7, 8]
])

I can do it

b[a[:, 0], a[:, 1]]

But this will be an “ out of boundsexception because 9 is out of range. I need a very fast way to slice an array by indexes, and that would be ideal if I can set the value of the clip, for example:

np.indexing_with_clipping(array=b, indices=a, clipping_value=0)
> array([0, 6, --> 0 = clipped value <--])
+4
source share
2 answers

Here's the approach -

def indexing_with_clipping(arr, indices, clipping_value=0):
    idx = np.where(indices < arr.shape,indices,clipping_value)
    return arr[idx[:, 0], idx[:, 1]]

Run Examples -

In [266]: arr
Out[266]: 
array([[0, 1, 2, 3],
       [5, 6, 7, 8]])

In [267]: indices
Out[267]: 
array([[0, 0],
       [1, 1],
       [1, 9]])

In [268]: indexing_with_clipping(arr,indices,clipping_value=0)
Out[268]: array([0, 6, 5])

In [269]: indexing_with_clipping(arr,indices,clipping_value=1)
Out[269]: array([0, 6, 6])

In [270]: indexing_with_clipping(arr,indices,clipping_value=2)
Out[270]: array([0, 6, 7])

In [271]: indexing_with_clipping(arr,indices,clipping_value=3)
Out[271]: array([0, 6, 8])

Focus on memory and performance, here's an approach that changes the indices inside a function -

def indexing_with_clipping_v2(arr, indices, clipping_value=0):
    indices[indices >= arr.shape] = clipping_value
    return arr[indices[:, 0], indices[:, 1]]

Run Example -

In [307]: arr
Out[307]: 
array([[0, 1, 2, 3],
       [5, 6, 7, 8]])

In [308]: indices
Out[308]: 
array([[0, 0],
       [1, 1],
       [1, 9]])

In [309]: indexing_with_clipping_v2(arr,indices,clipping_value=2)
Out[309]: array([0, 6, 7])
+1
source

You can use list comprehension:

b[
    [min(x,len(b[0])-1) for x in a[:,0]],
    [min(x,len(b[1])-1) for x in a[:,1]]
]

edit , min() , (, trenary)

edit2 , python-fu, , , , , :

clipping_value = -1
tmp=np.append(b,[[clipping_value],[clipping_value]],axis=1)
tmp[zip(*[((x,y) if (x<b.shape[0] and y<b.shape[1]) else (0,b.shape[1])) for (x,y) in zip(a.transpose()[0],a.transpose()[1])])]

, , ndarray tmp, b, clipping_value , , , b.

, zip numpy . . .

+1

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


All Articles