列表理解或 map() 或 for 循环访问前一行来操作数组

List comprehension or map() or for loop for accessing previous row to manipulate array

假设我有一个数组(numpy 数组)A = [[1, 2, 3], [0, 0, 0], [0, 0, 0]],我想将零行操作成 [2, 3, 1], [3, 1, 2],所以最终数组是 A = [[1, 2, 3], [2, 3, 1], [3, 1, 2]]

我可以使用如下所示的 for 循环来完成此操作:

a = np.array([[1, 2, 3],[0, 0, 0],[0, 0, 0]])
for i in xrange(1,3):
    a[i]=np.concatenate([a[i-1][1:], a[i-1][:1]], axis=1)

获取上一行,连接[1:]和[:1],分配结果作为下一行。

我有很多这样的循环,我想知道我是否可以摆脱 for 循环,从而获得更快的速度(也许?)。有没有办法使用列表理解或地图来做到这一点?除了第一行之外,我的 A 数组不必是零行的 nxn,它可以只是 A = [1, 2, 3, ..., n] 如果有一种方法我可以 创建 使用 A 的 nx3 数组作为初学者,继续获取前一行并将它的 [m:][:m] 连接起来。 (任意米)

或者是的,也许 for 循环是执行此类操作的 only/correct 方式。我想知道是不是。

for 循环是最简单的方法,列表理解或映射不会获得太多速度。但是您可以使用 roll 而不是串联:

a = numpy.array([1, 2, 3])
a = numpy.vstack([numpy.roll(a, -i) for i in xrange(3)])

我建议使用 python zip 内置 function.You 的方法可以将您的数组与其自身连接起来,然后您只需挑选每 3 个跟随的元素!

>>> A=np.arange(1,4)
>>> B=np.concatenate((A,A))
>>> B
array([1, 2, 3, 1, 2, 3])
>>> np.array(zip(B,B[1:],B[2:])[:-1])
array([[1, 2, 3],
       [2, 3, 1],
       [3, 1, 2]])

您可以将此方法用于更长的数组:

>>> A=np.arange(1,6)
>>> B=np.concatenate((A,A))
>>> np.array(zip(B,B[1:],B[2:])[:-1])
array([[1, 2, 3],
       [2, 3, 4],
       [3, 4, 5],
       [4, 5, 1],
       [5, 1, 2],
       [1, 2, 3],
       [2, 3, 4]])
>>> 

这是避免 Python 中循环的解决方案。 您可以通过创建一个索引数组来获得所需的输出,您可以使用它来索引您的原始数组:

In [40]:

    a = np.arange(1, 4)
    i = np.arange(len(a))
    indexer = i - np.atleast_2d(i).T 
    a[indexer]

Out[40]:
array([[1, 2, 3],
       [3, 1, 2],
       [2, 3, 1]])

这适用于任何 aindexer 数组是所需输出的大小,是使用广播创建的。在这种情况下,它看起来像

array([[ 0,  1, 2], 
       [-1,  0, 1], 
       [-2, -1, 0]])

以下是与循环方法的一些时间比较,表明它要快得多:

In [69]:

%%timeit 
a = np.arange(1, 11)
i = np.arange(0, len(a), step_size)
indexer = i - np.atleast_2d(i).T 
a[indexer]
10000 loops, best of 3: 14.7 µs per loop

In [70]:

%%timeit
a = numpy.arange(1, 11)
a = numpy.vstack([numpy.roll(a, -i) for i in xrange(len(a))])
10000 loops, best of 3: 143 µs per loop

In [71]:

%%timeit 
a = np.arange(1, 101)
i = np.arange(0, len(a), step_size)
indexer = i - np.atleast_2d(i).T 
a[indexer]
10000 loops, best of 3: 80 µs per loop

In [72]:

%%timeit
a = numpy.arange(1, 101)
a = numpy.vstack([numpy.roll(a, -i) for i in xrange(len(a))])
1000 loops, best of 3: 1.44 ms per loop

这样还有一个好处就是可以重复使用indexer以同样的方式操作其他相同长度的数组。如果你真的想要,你也可以将它写入磁盘。 对于任意步长 m,您可以执行以下操作:

In [61]:

m = 2
a = np.arange(1, 4)
i = np.arange(len(a))
indexer = (i - m * np.atleast_2d(i).T) % len(a)
a[indexer]

Out[61]:
array([[1, 2, 3],
       [2, 3, 1],
       [3, 1, 2]])