将数组切片为反向重叠子数组

Slice array into reversed overlapping subarrays

如何有效地将一个数组分割成重叠的子数组,以便

>>> N = 5
>>> L = 2  # could be any, less than N
>>> x = range(N)

预期结果是

[[1,0],[2,1],[3,2],[4,3]]

这是我尝试过的:

>>> [ x[i:i-L:-1] for i in range(L-1,len(x)) ]
[[], [3, 2], [4, 3], [5, 4]]  # wrong

>>> [ x[i:i-L:-1] for i in range(L,len(x)) ]
[[2, 1], [3, 2], [4, 3]]  # wrong

>>> [ x[i:i-L if i-L >= 0 else None:-1] for i in range(L-1,len(x)) ]
[[1, 0], [2, 1], [3, 2], [4, 3]]  # correct

它产生了预期的结果,但这是实现它的最佳方式吗?

是否有一些 numpy、itertools 函数可以提供帮助?

您可以使用简单的列表理解

>>> [[x[i+1], x[i]] for i in range(len(x) - 1)]
[[1, 0], [2, 1], [3, 2], [4, 3]]

或使用itertools.izip:

>>> from itertools import izip
>>> [list(k) for k in izip(x[1:], x)]
[[1, 0], [2, 1], [3, 2], [4, 3]]

我看到你更新了问题,所以这是使用 itertools.izipitertools.islice 和 [=30 的通用 itertools 方法=]itertools.imap

>>> res = imap(lambda i:islice(reversed(x), i, i+L), xrange(N-L,-1,-1))
>>> [list(e) for e in res]
[[1, 0], [2, 1], [3, 2], [4, 3]]

甚至纯发电机:

>>> res = (reversed(x[i:i+L]) for i in xrange(N-L+1))
>>> [list(e) for e in res]
[[1, 0], [2, 1], [3, 2], [4, 3]]

我假设输入是一个 NumPy 数组。所以,如果它还没有,我们可以将它作为一个带有 np.asarray() 的数组。因此,如果输入是一个列表,我们将从 : x = np.asarray(input_list) 开始。因此,以此为设置让我们尝试解决问题。

这是一种使用 strides that uses the concept of 的方法,它避免了复制,因此必须非常有效 -

L = 2 # Row length
strided = np.lib.stride_tricks.as_strided
n = x.strides[0]
out = strided(x[L-1:],shape=(x.size-L+1,L),strides=(n,-n))

样本运行 -

In [85]: L = 2

In [86]: strided(x[L-1:],shape=(x.size-L+1,L),strides=(n,-n))
Out[86]: 
array([[1, 0],
       [2, 1],
       [3, 2],
       [4, 3]])

In [87]: L = 3

In [88]: strided(x[L-1:],shape=(x.size-L+1,L),strides=(n,-n))
Out[88]: 
array([[2, 1, 0],
       [3, 2, 1],
       [4, 3, 2]])

In [89]: L = 4

In [90]: strided(x[L-1:],shape=(x.size-L+1,L),strides=(n,-n))
Out[90]: 
array([[3, 2, 1, 0],
       [4, 3, 2, 1]])

这是另一种使用 broadcasting -

的方法
L = 2 # Row length
out = x[np.arange(x.size-L+1)[:,None] + np.arange(L-1,-1,-1)]

或使用常规 zip(生成元组列表)

In [158]: x=list(range(5))
In [159]: x[1:],x[0:-1]
Out[159]: ([1, 2, 3, 4], [0, 1, 2, 3])
In [160]: list(zip(x[1:],x[0:-1]))
Out[160]: [(1, 0), (2, 1), (3, 2), (4, 3)]

或列表

In [161]: [list(i) for i in zip(x[1:],x[0:-1])]
Out[161]: [[1, 0], [2, 1], [3, 2], [4, 3]]

这是zip的使用,是一种转置。 numpy 数组也很容易转置:

In [167]: arr=np.array((x[1:],x[:-1]))
In [168]: arr
Out[168]: 
array([[1, 2, 3, 4],
       [0, 1, 2, 3]])
In [169]: arr.T.tolist()
Out[169]: [[1, 0], [2, 1], [3, 2], [4, 3]]

请注意,我必须将清单复印两份。 Divakar 的 stride_tricks 方法是在不复制的情况下创建重叠 'windows' 的唯一方法。这是一个更高级的方法。

对于小型列表,我建议坚持使用列表方法。创建数组会产生开销。