将阵列切成反向重叠的子阵列

时间:2016-11-30 17:05:45

标签: arrays python-2.7 numpy slice

如何有效地将数组切片为重叠的子数组,以便

>>> 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函数?

3 个答案:

答案 0 :(得分:1)

您可以使用简单列表理解

>>> [[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.isliceitertools.imap

这里采用通用itertools方式
>>> 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]]

答案 1 :(得分:1)

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

这是一种使用strides的方法,它使用views的概念,避免制作副本,因此必须非常有效 -

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

答案 2 :(得分: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方法是创建重叠窗口的唯一方法。没有复制。这是一种更先进的方法。

对于小型列表,我建议坚持使用列表方法。与创建数组相关的开销。