我追求的是Python代码能够使用numpy反转每个数组反对角线中的值的顺序。
我已经尝试过
np.rot90
、np.fliplr
、np.transpose
、np.flipud
的各种组合,但没有一个能够给我 5x3 数组的原始形状,其中所有对角线都反转了。
知道如何实现这一点吗?
示例:
[[ 1 2 4]
[ 3 5 7]
[ 6 8 10]
[ 9 11 13]
[12 14 15]]
应该变成:
[[ 1 3 6]
[ 2 5 9]
[ 4 8 12]
[ 7 11 14]
[10 13 15]]
我想这一定很简单,但不知何故,我还没有找到如何在具有数百万个值的数组上有效地完成它。
受到已经提供的答案(状态 2024-05-23 11:37 CET)的启发,并重新思考完成所需转换的最有效方法是什么,似乎给出一个带有两个索引的简单函数:
Column-X
,Row-y
数组中的值并返回访问数组所需的索引,就像在对角线上翻转/反转一样,将提供最快的结果。使用这样的函数,数组的对角线翻转版本将获得正确的值,而无需对数组进行操作,就像下面演示的简单情况一样简单:
>>> srcArr
array([[ 1, 2, 3, 4, 5, 6],
[ 7, 8, 9, 10, 11, 12],
[13, 14, 15, 16, 17, 18],
[19, 20, 21, 22, 23, 24]])
>>> def oneBasedXY(column, row):
... return ( row - 1, column - 1 )
...
>>> srcArr[oneBasedXY(3,4)]
21
>>> srcArr[(3,4)]
23
从这个角度来看,问题归结为提供函数代码
flipTheOtherDiagonals()
我认为没有任何有效的方法可以做到这一点。我的做法与我在这个答案中所说的从对角线创建数组类似,但一路上反转对角线。
import numpy as np
from scipy.sparse import diags
a = np.arange(15).reshape(5,3) + 1
n, m = a.shape
print(a)
offsets = np.arange(n+m-1)[::-1]-(a.shape[0]-1)
aflipped = np.fliplr(a)
diagonals = [np.diagonal(aflipped, offset=i) for i in offsets]
b = np.zeros_like(a)
for diagonal, offset in zip(diagonals, offsets):
b += diags(diagonal[::-1], offset, shape=a.shape).astype(int)
b = np.fliplr(b)
print(b)
只要没有更好的答案演示如何避免使用 Python 循环,下面的方法仅使用 numpy 并支持具有任何类型值(也可以是混合)的数组:
#!/usr/bin/python
import numpy as np
## Decide the shape of the test array :
M =3 ; N=5 # ( M-Rows x N-Columns )
## Create a test array :
srcArr = np.arange( 11, 10+N*M+1,
dtype=np.uint8).reshape(M,N) ; print( srcArr ); print( " ---===--- " )
# ---===---===---===---===---===---===---===---===---===---===---===---===---===---===---===---
## Extend the array to the right with M-1 columns for later "shear" :
tmpArr=np.zeros((M,M-1), dtype=np.uint8) ;# print(tmpArr );print( " ---===--- " )
extArr=np.concatenate( ( srcArr, tmpArr ), axis=1 ) ; print( extArr ); print( " ---===--- " )
## Share the extended array using np.roll() :
for index in range( 1, M):
extArr[index]=np.roll(extArr[index], index)
pass; print( extArr ); print( " ---===--- " )
## And reverse by up/down flipping the order of the former diagonals being now columns :
flpArr = np.flipud(extArr) ; print( flpArr ); print( " ---===--- " )
## Diagonals are reversed and will be "rolled" into their former positions in the array :
for index in range( 0, M +N - 1):
if True : ## The "tricky" part because handling non-square arrays requires handling
flpArr[:,index]=np.roll( flpArr[:,index], ## of three algorithmic different phases
( index + 1 ) if index < min(N,M) ## < Phase A : left, "growing" part of array
else ( -1 * (M + abs(N-M) ) + 2* (index + 1 - min(N,M)) ) ## Phase B :
* ( 1 if ( M - min(N,M) ) and (N+M-1 - 2*N - 1) ## < same "size":
else 0 ) if index < (N+M) - min(N,M) - 1
else -(M+N ) + index + 1 ) ## < Phase C : right, "shinking"
pass; print(flpArr) ; print( " ---===--- " )
for index in range( 1, M): ## Rolling the array back to its initial shape :
flpArr[index]=np.roll( flpArr[index], -index)
pass; print( flpArr) ; print( " ---===--- " )
tgtArr = flpArr[ :M, :N] ## < cut the final array out of the extended one
pass; print(tgtArr) ; print( " ---===--- " )
"""
[[ 1 2 3]
[ 4 5 6]
[ 7 8 9]
[ 10 11 12]
[13 14 15]]
[[ 1 2 3]
[ 4 5 6]
[ 7 8 9]
[10 11 12]
[13 14 15]]
[[ 1 2 3]
[ 4 5 6]
[ 7 8 9]
[10 11 12]
[13 14 15]]
"""
代码输出:
[[11 12 13 14 15]
[16 17 18 19 20]
[21 22 23 24 25]]
---===---
[[11 12 13 14 15 0 0]
[16 17 18 19 20 0 0]
[21 22 23 24 25 0 0]]
---===---
[[11 12 13 14 15 0 0]
[ 0 16 17 18 19 20 0]
[ 0 0 21 22 23 24 25]]
---===---
[[ 0 0 21 22 23 24 25]
[ 0 16 17 18 19 20 0]
[11 12 13 14 15 0 0]]
---===---
[[11 16 21 22 23 0 0]
[ 0 12 17 18 19 24 0]
[ 0 0 13 14 15 20 25]]
---===---
[[11 16 21 22 23 0 0]
[12 17 18 19 24 0 0]
[13 14 15 20 25 0 0]]
---===---
[[11 16 21 22 23]
[12 17 18 19 24]
[13 14 15 20 25]]
---===---
上面的输出演示了使用 numpy
np.roll()
的方法,可以“剪切”数组,以便首先获得可用于翻转的对角线,然后将其展开回原始形状。