从 numpy 数组中以步长 m 切片 n 个元素

Slicing n elements with stride m from numpy array

我想找到一种简洁的方法从 numpy 数组中以步长 m 对 n 个连续元素进行采样。最简单的情况是用 stride 2 采样 1 个元素,这意味着获取列表中的所有其他元素,可以这样完成:

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

但是,如果我想以 m 步幅对 n 个连续元素进行切片,其中 n 和 m 可以是任何整数怎么办?例如,如果我想以 3 的步幅对 2 个连续的元素进行切片,我会得到这样的结果:

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

是否有一种 Pythonic 和简洁的方法来做到这一点?谢谢!

这段代码可能会有用,我在问题中的例子(n=2,m=3)上进行了测试

import numpy as np

def get_slice(arr, n, m):
    b = np.array([])
    for i in range(0, len(arr), m):
        b = np.concatenate((b, arr[i:i + n]))
    return b

sliced_arr = get_slice(np.arange(10), n=2, m=3)
print(sliced_arr)

输出

[0. 1. 3. 4. 6. 7. 9.]

如果 a 足够长,您可以重塑、切片和拆开

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

但是a必须是(9,)或(12,)。结果仍然是一个副本。

建议:

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

也是副本。 as_strided 部分是一个视图,但 ravel 将制作一个副本。还有那个额外元素的丑陋。

sliding_window_view 添加为更安全的版本:

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

再次ravel 将进行复制。这省略了“额外” 9.

np.resize 执行带填充的 reshape(根据需要重复 a):

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