迭代通过2D数组的“正交”对角线的更多numpy方式

时间:2013-01-10 12:48:13

标签: python numpy

我有以下代码沿着与np.diagonal通常返回的对角线正交的对角线进行迭代。它从位置(0,0)开始,朝向右下角坐标。

代码按预期工作,但是它的所有循环都不是很简单,并且必须创建许多数组才能完成这个技巧。

所以我想知道是否有更好的方法可以做到这一点,因为我不知道如何跨越我的阵列或使用numpy的对角线方法以更好的方式做到(尽管我期待那里)是我看不到的一些技巧。)

import numpy as np

A = np.zeros((4,5))

#Construct a distance array of same size that uses (0, 0) as origo
#and evaluates distances along first and second dimensions slightly
#differently so that no values in the array is the same
D = np.zeros(A.shape)
for i in range(D.shape[0]):
    for j in range(D.shape[1]):
        D[i, j] = i * (1 + 1.0 / (grid_shape[0] + 1)) + j

print D
#[[ 0.          1.          2.          3.          4.        ]
# [ 1.05882353  2.05882353  3.05882353  4.05882353  5.05882353]
# [ 2.11764706  3.11764706  4.11764706  5.11764706  6.11764706]
# [ 3.17647059  4.17647059  5.17647059  6.17647059  7.17647059]]

#Make a flat sorted copy
rD = D.ravel().copy()
rD.sort()

#Just to show how it works, assigning incrementing values
#iterating along the 'orthagonal' diagonals starting at (0, 0) position
for i, v in enumerate(rD):

    A[D == v] = i

print A
#[[ 0  1  3  6 10]
# [ 2  4  7 11 14]
# [ 5  8 12 15 17]
# [ 9 13 16 18 19]]

修改

为了澄清,我希望在整个A中逐个元素地迭代,但是按照上面的代码调用的顺序(在最终的print中显示)。

迭代沿着对角线(如果1和2切换放置,以及A中的3和5等)沿着哪个方向并不重要,只是对角线与A的主对角线正交(一个由np.diag(A)生成的。

此问题的申请/原因在我之前的问题中(在该问题底部的解决方案部分):Constructing a 2D grid from potentially incomplete list of candidates

3 个答案:

答案 0 :(得分:4)

这是一种避免Python for循环的方法。

首先,让我们看看我们的附加表:

import numpy as np
grid_shape = (4,5)
N = np.prod(grid_shape)

y = np.add.outer(np.arange(grid_shape[0]),np.arange(grid_shape[1]))
print(y)

# [[0 1 2 3 4]
#  [1 2 3 4 5]
#  [2 3 4 5 6]
#  [3 4 5 6 7]]

关键的想法是,如果我们按顺序访问加法表中的总和,我们将按所需顺序迭代数组。

我们可以使用np.argsort找出与该订单相关联的指数:

idx = np.argsort(y.ravel())
print(idx)
# [ 0  1  5  2  6 10  3  7 11 15  4  8 12 16  9 13 17 14 18 19]

idx是金色的。它基本上是遍历任何2D形状阵列(4,5)所需的一切,因为2D阵列只是重新整形的一维阵列。

如果您的最终目标是生成您在帖子末尾显示的数组A,那么您可以再次使用argsort

print(np.argsort(idx).reshape(grid_shape[0],-1))
# [[ 0  1  3  6 10]
#  [ 2  4  7 11 14]
#  [ 5  8 12 15 17]
#  [ 9 13 16 18 19]]

或者,如果您需要为A分配其他值,或许这会更有用:

A = np.zeros(grid_shape)
A1d = A.ravel()
A1d[idx] = np.arange(N)  # you can change np.arange(N) to any 1D array of shape (N,)
print(A)
# [[  0.   1.   3.   6.  10.]
#  [  2.   4.   7.  11.  15.]
#  [  5.   8.  12.  16.  18.]
#  [  9.  13.  14.  17.  19.]]

我知道你要求通过你的数组迭代的方法,但是我想展示上面的内容,因为通过全数组赋值或numpy函数调用(如np.argsort)生成数组就像完成一样上面可能会比使用Python循环更快。但是如果你需要使用Python循环,那么:

for i, j in enumerate(idx):
   A1d[j] = i

print(A)
# [[  0.   1.   3.   6.  10.]
#  [  2.   4.   7.  11.  15.]
#  [  5.   8.  12.  16.  18.]
#  [  9.  13.  14.  17.  19.]]

答案 1 :(得分:3)

>>> D
array([[ 0,  1,  2,  3,  4],
       [ 5,  6,  7,  8,  9],
       [10, 11, 12, 13, 14],
       [15, 16, 17, 18, 19]]) 

>>> D[::-1].diagonal(offset=1)
array([16, 12,  8,  4])
>>> D[::-1].diagonal(offset=-3)
array([0])
>>> np.hstack([D[::-1].diagonal(offset=-x) for x in np.arange(-4,4)])[::-1]
array([ 0,  1,  5,  2,  6, 10,  3,  7, 11, 15,  4,  8, 12, 16,  9, 13, 17,
       14, 18, 19])

只要它不是一个大矩阵就更简单。

答案 2 :(得分:1)

我不确定这是否是你真正想要的,但也许:

>>> import numpy as np
>>> ar = np.random.random((4,4))
>>> ar
array([[ 0.04844116,  0.10543146,  0.30506354,  0.4813217 ],
       [ 0.59962641,  0.44428831,  0.16629692,  0.65330539],
       [ 0.61854927,  0.6385717 ,  0.71615447,  0.13172049],
       [ 0.05001291,  0.41577457,  0.5579213 ,  0.7791656 ]])
>>> ar.diagonal()
array([ 0.04844116,  0.44428831,  0.71615447,  0.7791656 ])
>>> ar[::-1].diagonal()
array([ 0.05001291,  0.6385717 ,  0.16629692,  0.4813217 ])

修改 作为一般解决方案,对于任意形状的数组,您可以使用

import numpy as np
shape = tuple([np.random.randint(3,10) for i in range(2)])
ar = np.arange(np.prod(shape)).reshape(shape)
out = np.hstack([ar[::-1].diagonal(offset=x) \
                for x in np.arange(-ar.shape[0]+1,ar.shape[1]-1)])
print ar
print out

给出,例如

[[ 0  1  2  3  4]
 [ 5  6  7  8  9]
 [10 11 12 13 14]
 [15 16 17 18 19]
 [20 21 22 23 24]]
[ 0  5  1 10  6  2 15 11  7  3 20 16 12  8  4 21 17 13  9 22 18 14 23 19]