简体   繁体   中英

how to get the neighboring elements in a numpy array with taking boundaries into account?

I want to get the neighbors of the certain element in the numpy array. Lets consider following example

    a = numpy.array([0,1,2,3,4,5,6,7,8,9])

So I want to specify position 5 and want to get three neighbors from both sides. It can be done

   index = 5
   num_neighbor=3
   left = a[index-num_neighbor:index]
   right= a[num_neighbor+1:num_neighbor+index+1]

The above code does not take care of the boundaries... I want that i get the neighbours within the boundaries of the array. For this consider the following example if index is 1 then the left neighbor is only one element which is 0.

Thanks a lot

left = a[max(0,index-num_neighbor):index]
import numpy as np
a = np.array([0,1,2,3,4,5,6,7,8,9])
num_neighbor=3    

for index in range(len(a)):
    left = a[:index][-num_neighbor:]
    right= a[index+1:num_neighbor+index+1]
    print(index,left,right)

yields

(0, array([], dtype=int32), array([1, 2, 3]))
(1, array([0]), array([2, 3, 4]))
(2, array([0, 1]), array([3, 4, 5]))
(3, array([0, 1, 2]), array([4, 5, 6]))
(4, array([1, 2, 3]), array([5, 6, 7]))
(5, array([2, 3, 4]), array([6, 7, 8]))
(6, array([3, 4, 5]), array([7, 8, 9]))
(7, array([4, 5, 6]), array([8, 9]))
(8, array([5, 6, 7]), array([9]))
(9, array([6, 7, 8]), array([], dtype=int32))

The reason why a[index-num_neighbor:index] does not work when index<num_neighbor is because of slicing rules #3 and #4 :

Given s[i:j] :

If i or j is negative, the index is relative to the end of the string: len(s) + i or len(s) + j is substituted.

The slice of s from i to j is defined as the sequence of items with index k such that i <= k < j. If i or j is greater than len(s), use len(s). If i is omitted or None, use 0. If j is omitted or None, use len(s). If i is greater than or equal to j, the slice is empty.

So when index=1 , then a[index-num_neighbor:index] = a[-2:1] = a[10-2:1] = a[8:1] = [] .

The method I came up with involves slicing the array and then padding as necessary to fill out-of-bounds values.

Taken from here :

def surrounding(x, idx, radius=1, fill=0):
""" 
Gets surrounding elements from a numpy array 

Parameters: 
x (ndarray of rank N): Input array
idx (N-Dimensional Index): The index at which to get surrounding elements. If None is specified for a particular axis,
    the entire axis is returned.
radius (array-like of rank N or scalar): The radius across each axis. If None is specified for a particular axis, 
    the entire axis is returned.
fill (scalar or None): The value to fill the array for indices that are out-of-bounds.
    If value is None, only the surrounding indices that are within the original array are returned.

Returns: 
ndarray: The surrounding elements at the specified index
"""

assert len(idx) == len(x.shape)

if np.isscalar(radius): radius = tuple([radius for i in range(len(x.shape))])

slices = []
paddings = []
for axis in range(len(x.shape)):
    if idx[axis] is None or radius[axis] is None:
        slices.append(slice(0, x.shape[axis]))
        paddings.append((0, 0))
        continue

    r = radius[axis]
    l = idx[axis] - r 
    r = idx[axis] + r

    pl = 0 if l > 0 else abs(l)
    pr = 0 if r < x.shape[axis] else r - x.shape[axis] + 1

    slices.append(slice(max(0, l), min(x.shape[axis], r+1)))
    paddings.append((pl, pr))

if fill is None: return x[slices]
return np.pad(x[slices], paddings, 'constant', constant_values=fill)

Python takes care of boundaries for you:

>>> a = [0,1,2,3,4,5,6,7,8,9]
>>> a[-100 : 1000]
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
>>> a[-100:3]
[0, 1, 2]

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