[SOLVED] Slicing n elements with stride m from numpy array

Issue

I want to find a concise way to sample n consecutive elements with stride m from a numpy array. The simplest case is with sampling 1 element with stride 2, which means getting every other element in a list, which can be done like this:

>>> a = np.arange(10)
>>> a
array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])
>>> a[::2]
array([0, 2, 4, 6, 8])

However, what if I wanted to slice n consecutive elements with a stride of m where n and m can be any integers? For example, if I wanted to slice 2 consecutive elements with a stride of 3 I would get something like this:

array([0, 1, 3, 4, 6, 7, 9])

Is there a pythonic and concise way of doing this? Thank you!

Solution

If a is long enough you could reshape, slice, and ravel

a.reshape(-1,3)[:,:2].ravel()

But a has to be (9,) or (12,). And the result will still be a copy.

The suggested:

np.lib.stride_tricks.as_strided(a, (4,2), (8*3, 8)).ravel()[:-1]

is also a copy. The as_strided part is a view, but ravel will make a copy. And there is the ugliness of that extra element.

sliding_window_view was added as a safer version:

In [81]: np.lib.stride_tricks.sliding_window_view(a,(3))
Out[81]: 
array([[0, 1, 2],
       [1, 2, 3],
       [2, 3, 4],
       [3, 4, 5],
       [4, 5, 6],
       [5, 6, 7],
       [6, 7, 8],
       [7, 8, 9]])
In [82]: np.lib.stride_tricks.sliding_window_view(a,(3))[::3,:2]
Out[82]: 
array([[0, 1],
       [3, 4],
       [6, 7]])

Again ravel will make a copy. This omits the "extra" 9.

np.resize does a reshape with padding (repeating a as needed):

In [83]: np.resize(a, (4,3))
Out[83]: 
array([[0, 1, 2],
       [3, 4, 5],
       [6, 7, 8],
       [9, 0, 1]])
In [84]: np.resize(a, (4,3))[:,:2]
Out[84]: 
array([[0, 1],
       [3, 4],
       [6, 7],
       [9, 0]])

Answered By – hpaulj

Answer Checked By – Mary Flores (BugsFixing Volunteer)

Leave a Reply

Your email address will not be published. Required fields are marked *