使用numpy获取多维数组的所有对角线(包括小对角线)。

4

我试图获取多维对象的对角线(和反对角线)元素。

这些形状如(2,2), (3,3,3), (4,4,4,4), (5,5,5,5,5)等等。我认为这并不太相关。

我发现可以使用ndarray.diagonal方法获取对角线元素,但我找不到任何可以获取反对角线的方法。

那么,我需要自己手动实现吗?

[编辑] 所以对于

array([[[54, 81, 31],
        [ 4, 83, 18],
        [38, 32, 52]],

       [[ 2, 45, 87],
        [33, 20,  3],
        [85, 31, 35]],

       [[ 6, 11, 49],
        [39, 76, 75],
        [28, 52, 63]]])

所以我想要“水平”的对角线,如下:

[54, 45, 49],
[ 4. 20, 75],
etc.

但在某种程度上,它们也是水平的

[ 6, 45, 31],
[39, 20, 18]

然后还有“垂直”的选项,例如:

[54, 33, 28],
[81, 20, 52],
etc.

但是这些也是垂直的:

[6, 33, 38],
[11, 20, 32]

接下来这个,不过你可以怎么称呼它

[54, 20, 63]

还有一些“更长”的对角线,就像之前的那个一样(从几何意义上讲更长,如果你把矩阵看作一个三维几何结构,其中数字被放置在立方体的顶点和它们之间线段的中点上)。

[38, 20, 49],
[6, 20, 52]

接下来,一个小对角线是指在这个矩阵中从右到左或从底部到顶部(但不能同时两者)的一条线,类似于:

[31, 45, 6],
[31, 83, 38]  # this is the first classical anti-diagonal in the first matrix

当然,我没有把所有的对角线都列出来,但这是我的要求。我不需要那些偏离主/副对角线的对角线。
如果你也知道这是不可能的,请告诉我,因为那么我会手工完成它。

1
请列出一个多维数组案例,如(3,3,3)的样本输入和预期输出? - Divakar
3-D或4-D数组的(主要和反对)对角线是什么?因为它们有很多。 - JeD
@Divakar 是的...我想要它们全部。我想要每一个可能的对角线。我正在尝试构建一个多维版本的井字游戏。 - vlad-ardelean
@Divakar,如果一个主要的方向是从上到下和从左到右,那么一个次要的方向就会切换其中一个。我会想出一个通用的数学规则来满足我的需求。但我认为我已经得到了答案:在numpy中可能不可能实现,一旦我有了数学公式,用Python实现将是微不足道的。 - vlad-ardelean
顺序是否重要,即 [31, 45, 6] 而不是 [6, 45, 31] - Divakar
显示剩余2条评论
2个回答

1
这应该可以做到,使用numpy数组。它提供了一个生成器,其中包含与数组具有相同维数的所有对角线。 还提供了原始数组的视图(而不是副本)。 代码下面有解释。
import numpy as np
def get_diagonals_np(arr):
    if arr.ndim == 1:
        yield arr
    else:
        yield from get_diagonals_np(arr.diagonal())
        yield from get_diagonals_np(np.flip(arr, 0).diagonal())

# The function is recursive. How it works is best shown by example.
# 1d: arr = [0, 1] then the diagonal is also [0, 1].

# 2d: arr = [[0, 1],
#            [2, 3]]
# The numpy diagonal method gives the main diagonal = [0, 3], a 1d array
# which is recursively passed to the function.
# To get the opposite diagonal we first use the numpy flip function to
# reverse the order of the elements along the given dimension, 0 in this case.
# This gives [[2, 3],
#              0, 1]]
# The numpy diagonal method gives the main diagonal = [2, 1], a 2d array
# which is recursively passed to the function.

# 3d: arr = [[[0, 1],
#             [2, 3]],
#            [[4, 5],
#             [6, 7]]]
# The numpy diagonal method gives the main diagonals in the 3rd dimension
# as rows.
#            [[0, 6],
#             [1, 7]]
# Note that the diagonals of this array are [0, 7] and [6, 1] which are
# retrieved by a recurive call to the function.
# We now have 2 of the 4 3-agonals of the orginal 3d arr.
# To get the opposite 3-agonals we first use the numpy flip function which
# gives
#           [[[4, 5],
#             [6, 7]],
#            [[0, 1],
#             [2, 3]]]
# and a call to the numpy diagonal method gives
#            [[4, 2],
#             [5, 3]]
# The diagonals of this array are [4, 3] and [2, 5]
# We now have all four 3-agonals of the original 3d arr.

1
如果您想要从corner1corner2的对角线,并以以下形式定义角落:(0,0,0,...,0) , (0,0,0,....,1),...,(1,1,1,...,1),其中0表示“此维度为0”,1表示“此维度为-1/end”,则假设数组在每个维度上具有相同的大小,则此函数将返回从corner1corner2的值。请注意,保留HTML标签。
import numpy
def diagonal(arr,corner1,corner2):
    arr=numpy.array(arr)
    #Change values to fit array
    corner1Copy=(len(arr)-1)*numpy.array(corner1)
    corner2Copy=(len(arr)-1)*numpy.array(corner2)

    #create return array by running from corner1 to corner2 and returning the values
    return [arr[tuple((i*corner2Copy+(len(arr)-i-1)*corner1Copy)/(len(arr)-1))] for i in range(len(arr))]

这里有两个小的测试用例,但我建议创建更多的测试用例,以防我遗漏了什么:

arr=[[[i+j+k for i in range(5)]for j in range(5)] for k in range(5)]
corner1=[0,0,0]
corner2=[1,1,1]

#returns arr[0,0,0],arr[1,1,1],....,arr[-1,-1,-1]
print(diagonal(arr,corner1,corner2))
print([arr[i][i][i] for i in range(len(arr))])

arr2=[[i+j for i in range(5)]for j in range(5)]

corner12=[0,1]
corner22=[1,1]
#return arr[0,-1],arr[1,-1],....,arr[-1,-1]
print(diagonal(arr2,corner12,corner22))
print([arr2[i][-1] for i in range(len(arr2))])

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接