我有以下代码沿着与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
答案 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]