Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Numpy 2D array indexing without out of bound and with clipping value

I have indices array

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

And 2D array

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

I can do this one

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

But it'll be an exception 'out of bounds', because 9 is out of range. I need a very fast way to make array slice by indices and it will be ideal if I can set a clip value, e.g.:

np.indexing_with_clipping(array=b, indices=a, clipping_value=0)
> array([0, 6, --> 0 = clipped value <--])
like image 673
Max Tkachenko Avatar asked Sep 29 '16 12:09

Max Tkachenko


People also ask

How do I clip values in a NumPy array?

clip() function is used to Clip (limit) the values in an array. Given an interval, values outside the interval are clipped to the interval edges. For example, if an interval of [0, 1] is specified, values smaller than 0 become 0, and values larger than 1 become 1.

How can we create NumPy array explain indexing and slicing?

Indexing can be done in numpy by using an array as an index. In case of slice, a view or shallow copy of the array is returned but in index array a copy of the original array is returned. Numpy arrays can be indexed with other arrays or any other sequence with the exception of tuples.

How is a 2D array indexed?

Two-dimensional (2D) arrays are indexed by two subscripts, one for the row and one for the column. Each element in the 2D array must by the same type, either a primitive type or object type.

What is NumPy fancy indexing?

Fancy indexing is conceptually simple: it means passing an array of indices to access multiple array elements at once. For example, consider the following array: import numpy as np rand = np. random. RandomState(42) x = rand.


2 Answers

Here's an 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]]

Sample runs -

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])

With focus on memory and performance efficiency, here's an approach that modifies the indices within the function -

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

Sample run -

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])
like image 61
Divakar Avatar answered Oct 05 '22 17:10

Divakar


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 I used last array value as your clipping value, but you can replace the min() function with whatever you want (e.g. trenary operator)

edit2 OK, based on clarification in comments and all python-fu that I could put together, this snipped finally does what you need:

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])])]

It is the same as above, just creates ndarray tmp, which is a copy of b but contains the clipping_value as its last element and then uses my previous solution to set indices so, that they point to the last element if either of the indices is bigger than dimensions of b.

I learned that there is reverse to the zip function and that the numpy arrays accept lists as indices. It was fun. Thanks.

like image 23
grepe Avatar answered Oct 05 '22 18:10

grepe