遍历2D数组的“正交"对角线的更麻木的方式 [英] More numpy way of iterating through the 'orthogonal' diagonals of a 2D array

查看:94
本文介绍了遍历2D数组的“正交"对角线的更麻木的方式的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I have the following code that iterates along the diagonals that are orthogonal to the diagonals normally returned by np.diagonal. It starts at position (0, 0) and works its way towards the lower right coordinate.

该代码按预期工作,但其所有循环都不太麻木,而且效率低下,必须创建许多数组才能实现.

The code works as intended but is not very numpy with all its loops and inefficient in having to create many arrays to do the trick.

所以我想知道是否有更好的方法来执行此操作,因为我看不到如何跨步数组或使用numpy的对角线方法来实现更好的方法(尽管我希望有一些更好的方法)我看不到的把戏).

So I wonder if there is a nicer way to do this, because I don't see how I would stride my array or use the diagonal-methods of numpy to do it in a nicer way (though I expect there are some tricks I fail to see).

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中).

To clarify, I want to iterate element-wise through the entire A but doing so in the order the code above invokes (which is displayed in the final print).

仅沿着对角线正交于A的主对角线(如果产生了一个,则不重要),迭代沿对角线的哪个方向(如果1和2切换放置,而A中的3和5等)是不重要的通过np.diag(A)).

It is not important which direction the iteration goes along the diagonals (if 1 and 2 switched placed, and 3 and 5 etc. in A) only that the diagonals are orthogonal to the main diagonal of A (the one produced by np.diag(A)).

此问题的申请/原因在我之前的问题中(在该问题底部的解决方案部分中):

The application/reason for this question is in my previous question (in the solution part at the bottom of that question): Constructing a 2D grid from potentially incomplete list of candidates

推荐答案

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

Here is a way that avoids Python for-loops.

首先,让我们看一下加法表:

First, let's look at our addition tables:

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

关键思想是,如果我们按顺序访问加法表中的总和,我们将以所需的顺序遍历数组.

The key idea is that if we visit the sums in the addition table in order, we would be iterating through the array in the desired order.

我们可以使用np.argsort找出与该订单相关的索引:

We can find out the indices associated with that order using 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数组.

idx is golden. It is essentially everything you need to iterate through any 2D array of shape (4,5), since a 2D array is just a 1D array reshaped.

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

If your ultimate goal is to generate the array A that you show above at the end of your post, then you could use argsort again:

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分配其他值,也许这会更有用:

Or, alternatively, if you need to assign other values to A, perhaps this would be more useful:

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

我知道您要求通过数组进行 iterate 的方法,但是我想显示上面的内容,因为通过完成整个数组分配或numpy函数调用(如np.argsort)生成数组以上可能比使用Python循环更快.但是,如果您需要使用Python循环,则:

I know you asked for a way to iterate through your array, but I wanted to show the above because generating arrays through whole-array assignment or numpy function calls (like np.argsort) as done above will probably be faster than using a Python loop. But if you need to use a Python loop, then:

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

这篇关于遍历2D数组的“正交"对角线的更麻木的方式的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆