1

I have been searching if there is an standard mehtod to create a subarray using relative indexes. Take the following array into consideration:

>>> m = np.arange(25).reshape([5, 5])
array([[ 0,  1,  2,  3,  4],
       [ 5,  6,  7,  8,  9],
       [10, 11, 12, 13, 14],
       [15, 16, 17, 18, 19],
       [20, 21, 22, 23, 24]])

I want to access the 3x3 matrix at a specific array position, for example [2,2]:

>>> x = 2, y = 2
>>> m[slice(x-1,x+2), slice(y-1,y+2)]
array([[ 6,  7,  8],
       [11, 12, 13],
       [16, 17, 18]])

For example for the above somethig like m.subarray(pos=[2,2], shape=[3,3]) I want to sample a ndarray of n dimensions on a specific position which might change.

I did not want to use a loop as it might be inneficient. Scipy functions correlate and convolve do this very efficiently, but for all positions. I am interested only in the sampling of one.

The best answer could solve the issues at edges, in my case I would like for example to have wrap mode: (a b c d | a b c d | a b c d)

--------------------EDITED-----------------------------

Based on the answer from @Carlos Horn, I could create the following function.

def cell_neighbours(array, index, shape):  
    pads = [(floor(dim/2), ceil(dim / 2)) for dim in shape]
    array = np.pad(self.configuration, pads, "wrap")
    views = np.lib.stride_tricks.sliding_window_view
    return views(array, shape)[tuple(index)]

Last concern might be about speed, from docs: For many applications using a sliding window view can be convenient, but potentially very slow. Often specialized solutions exist.

From here maybe is easier to get a faster solution.

BorjaEst
  • 390
  • 2
  • 11
  • The comment about speed refers to aggregations using those windows, e.g. a rolling mean may not need to sum all values in all windows, but could only subtract the value that falls out of the window and add the one which enters etc. In your case, you just want to access matrices at a given position. Here, building the views is not the bottleneck, it is the padding which costs due to the copying of data, but likely not a big deal if your array is not gigantic. – Carlos Horn Jan 10 '23 at 20:55

1 Answers1

1

You could build a view of 3x3 matrices into the array as follows:

import numpy as np
m = np.arange(25).reshape(5,5)
m3x3view = np.lib.stride_tricks.sliding_window_view(m, (3,3))

Note that it will change slightly your indexing on half the window size meaning

x_view = x - 3//2
y_view = y - 3//2
print(m3x3view[x_view,y_view])  # gives your result

In case a copy operation is fine, you could use:

mpad = np.pad(m, 1, mode="wrap")
mpad3x3view = np.lib.stride_tricks.sliding_window_view(mpad, (3,3))
print(mpad3x3view[x % 5,y % 5])

to use arbitrary x, y integer values.

Carlos Horn
  • 1,115
  • 4
  • 17
  • Is a nice approach, but now I am testing, I might have an issue at the corners of the array. – BorjaEst Jan 10 '23 at 13:14
  • You can use `np.pad` before creating the array views. Note, that this will crate a copy of your initial matrix. See the edited of the answer. – Carlos Horn Jan 10 '23 at 15:26