2

我有以下代码沿着与通常返回的对角线正交的对角线进行迭代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代码,但是按照上面代码调用的顺序(显示在 final 中print)。

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

这个问题的应用程序/原因在我之前的问题中(在该问题底部的解决方案部分中):Constructing a 2D grid from 也许不完整的候选人列表

4

3 回答 3

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是金色的。它基本上是您遍历任何形状 (4,5) 的二维数组所需的一切,因为二维数组只是重新整形的一维数组。

如果您的最终目标是生成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.]]
于 2013-01-10T13:31:46.617 回答
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])

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

于 2013-01-10T13:39:10.753 回答
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]
于 2013-01-10T12:54:42.233 回答