numpy 迭代2D数组的“正交”对角线的更乏味的方法

ohtdti5x  于 2023-06-23  发布在  其他
关注(0)|答案(4)|浏览(110)

下面的代码沿着与np.diagonal通常返回的对角线正交的对角线进行迭代。它从位置(0,0)开始,并向右下坐标移动。
代码按预期工作,但所有循环都不是很numpy,并且必须创建许多数组才能做到这一点。
所以我想知道是否有更好的方法来做到这一点,因为我不知道如何跨越我的数组或使用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切换放置,以及3和5切换放置等)。在A中),只有对角线与A的主对角线正交(由np.diag(A)产生的对角线)。
这个问题的应用/原因在我之前的问题中(在该问题底部的解决方案部分):Constructing a 2D grid from potentially incomplete list of candidates

uplii1fm

uplii1fm1#

这里有一个避免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是金色的。它基本上是迭代任何形状(4,5)的2D数组所需的一切,因为2D数组只是重塑的1D数组。
如果你的最终目标是生成你在文章末尾显示的数组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.]]
mqxuamgl

mqxuamgl2#

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

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

olqngx59

olqngx593#

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

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

t30tvxxf4#

直观的循环

对于那些(像我一样)正在寻找直观的嵌套for循环的人。

**注意:**计算效率低下!

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

n1, n2 = A.shape
for k in range(n1+n2-1):
    for i in range(k+1):
        j = k - i
        if (i < n1) and (j < n2):
            print(A[i, j], end=' ')
# 0 1 5 2 6 10 3 7 11 15 4 8 12 16 9 13 17 14 18 19

相关问题