获取numpy数组的对角线相反方向

42

在numpy数组中有一个内置函数用于获取对角线索引,但我似乎无法弄清如何从右上角开始获取对角线。

这是用于从左上角开始获取对角线的正常代码:

>>> import numpy as np
>>> array = np.arange(25).reshape(5,5)
>>> diagonal = np.diag_indices(5)
>>> array
array([[ 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]])
>>> array[diagonal]
array([ 0,  6, 12, 18, 24])

如果我希望它返回什么,我该使用什么?

array([ 4,  8, 12, 16, 20])
3个回答

52

In [47]: np.diag(np.fliplr(array))
Out[47]: array([ 4,  8, 12, 16, 20])
或者
In [48]: np.diag(np.rot90(array))
Out[48]: array([ 4,  8, 12, 16, 20])

在这两个操作中,np.diag(np.fliplr(array)) 更快:

In [50]: %timeit np.diag(np.fliplr(array))
100000 loops, best of 3: 4.29 us per loop

In [51]: %timeit np.diag(np.rot90(array))
100000 loops, best of 3: 6.09 us per loop

4
你开始计时了,所以这是我尽力让它快速的最佳方案:step = len(array) - 1; np.take(array, np.arange(step, array.size, step)) - Jaime
@Jaime:太棒了——比我的解决方案快多了。也许我们需要np.arange(step, array.size-1, step)?请将其发布为解决方案,以便我可以投票支持。 - unutbu
2
我在我的立方体墙上挂着Tim Peters的Python之禅,就在我的显示器旁边。当“可读性至上”这个要求盯着我时,我不能将评论代码发布为答案... :P你用fliplr的解决方案可能是最好的:足够快,并且在几个月后重新审视时更易于理解。 - Jaime
@Jaime,你会一直输掉那些时间,因为对角线创建了一个视图(或在新版本中将创建)。 - seberg
@Jaime - 我对我的解决方案的_zenniness_毫不犹豫:np.diag(arr[:, ::-1] ;) - 请看下面的答案! - n1k31t4

4
这是使用numpy切片的简单方法。我个人认为它不会太难看,但同意fliplr更具描述性。
仅为了强调此示例对现有答案的贡献,我运行了相同的简单基准测试:
In [1]: import numpy as np

In [3]: X = np.random.randint(0, 10, (5, 5))

In [4]: X
Out[4]: 
array([[7, 2, 7, 3, 7],
       [8, 4, 5, 9, 6],
       [0, 2, 9, 0, 4],
       [8, 2, 1, 0, 3],
       [3, 1, 0, 7, 0]])

In [5]: Y = X[:, ::-1]

In [6]: Z1 = np.diag(Y)

In [7]: Z1
Out[7]: array([7, 9, 9, 2, 3])

与最快替代方案的奇偶性比较:

In [8]: step = len(X) - 1

In [9]: Z2 = np.take(X, np.arange(step, X.size-1, step))

In [10]: Z2
Out[10]: array([7, 9, 9, 2, 3])

In [11]: np.array_equal(Z1, Z2)
Out[11]: True

基准测试

In [12]: %timeit np.diag(X[:, ::-1])
1.92 µs ± 29.5 ns per loop (mean ± std. dev. of 7 runs, 1000000 loops each)

In [13]: %timeit step = len(X) - 1; np.take(X, np.arange(step, X.size-1, step))
2.21 µs ± 246 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)

初步比较表明,我的解决方案在复杂度上另外还是线性的,而使用第二个“步骤”解决方案则不是。

In [14]: big_X = np.random.randint(0, 10, (10000, 10000))

In [15]: %timeit np.diag(big_X[:, ::-1])
2.15 µs ± 96.3 ns per loop (mean ± std. dev. of 7 runs, 1000000 loops each)

In [16]: %timeit step = len(big_X) - 1; np.take(big_X, np.arange(step, big_X.size-1, step))
100 µs ± 1.85 µs per loop (mean ± std. dev. of 7 runs, 10000 loops each)

我通常使用这种方法来翻转图像(镜像),或者在opencv的格式(通道,高度,宽度)matplotlib的格式(高度,宽度,通道)之间进行转换。因此,对于一个三维图像,它只需flipped = image[:, :, ::-1]。当然,您可以通过将::-1部分放在所需的维度中来推广它以沿任何维度翻转。


3
以下是两个想法:
step = len(array) - 1

# This will make a copy
array.flat[step:-step:step]

# This will make a veiw
array.ravel()[step:-step:step]

第二个可能会复制 ;) - seberg

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