Reputation: 159
I'm wonder how can I undo my transpose operation. Let me be more specific in example:
a = np.random.rand(25,32,11)
b = a.transpose(2,0,1)
c = b.transpose(??) ### Here I should set (1,0,2)
# c == a
Which exactly values should I set in last transpose to make c == a ? In numpy there is not such method as "transpose_undo" I guess. As an solution we can rely on actual shape of array, but we can have 25x25x25 array in the future...
Upvotes: 1
Views: 296
Reputation: 311
Let me first clearly explain how to calculate permutation argument: For example, imagine if we want to get permutation argument of transposing an array of size (i, j, k) into (k, i, j). To calculate the permutation argument, first you must number each axis pythonically, so in given example: "i" is axis=0, "j" is axis =1, and "k" is axis=2. Then, you should maintain original axis numbers and arrange those numbers into final desired axes arrangement, as in: "i" should be placed in axis=1 and "i" was represented by number 0 so 0 sits in position of axis=1 which gives => ( ?, 0, ?), and by maintaining the same condition for other axes the permutation argument of (2,0,1) will be obtained. However, It is easy to mistake final axis numbers instead of the original ones in calculating the permutation argument, like mistakenly considering: "i" should become axis=1, "j" should become axis=2, and "k" should become axis=0, which gives wrong value of (1, 2, 0). In some cases, even if you choose the second method (the wrong one) you might end up getting the right answer if rearrangement change is symmetrical from point of view of a middle axis which splits axes equally (in 3 dimension it is axis=1 but for example in 4 dimension it is an imaginary axis between axis=1 and axis=2), for example if you want to reshape (a, b, c) into (c,b,a), both methods yield permutation argument of (2, 1, 0). So, it is easy to think your wrong method is right and wonder why it does not work for some specific reshapes!
In your example, you changed an array of size (i, j ,k) by permutation number of (2, 0, 1), so by maintaining number of axes according to what has been said above we'll have: (i=0, j=1 ,k=1) so final arrangement (=permutation argument) of (2, 0, 1) gives: (2= k, 0=i, 1=j). now your new array has size of (k, i, j). Then again, you want to transpose (k, i, j) back into (i, j, k). so by updating axes for each dimension we'll have: (k=0, i=1, j=2), thus axes arrangement of (i, j, k) produces (i=1, j=2, k=0) or simply as (1, 2, 0).
I automated this procedure below. However, I don't think it is really necessary because these rare cases in reshaping arrays can be easily calculated by yourself when you know the correct method):
# functions to produce shape of transposed array after permutation and the permutation argument
import numpy as np
def permutation_result(a_,p):
"""
returns transposed shape of array "a" when permutation argument is given
a_ = np.shape(a) ; p = permutation argument
"""
le = len(a_) # number of dimensions
dim = np.zeros(le)
for q in range(le):
dim[q] = a_[q]
axes = np.zeros((le,2))
for q in range(le):
axes[q][0] = dim[q]
axes[q][1] = q
b_ = np.zeros(le) # b sizes
for m in range(le):
b_[m] = axes[np.argwhere(axes==p[m])[0,0]][0] # only rows are important
return b_
def permutation_arg(a_,b_):
"""
returns permutation argument when array "a" is transposed into array "b"
a_ = np.shape(a) ; b_ = np.shape(b)
"""
a_ = np.shape(a)
le = len(a_) # number of dimensions
dim = np.zeros(le)
for q in range(le):
dim[q] = a_[q]
axes = np.zeros((le,2))
for q in range(le):
axes[q][0] = dim[q]
axes[q][1] = q
p = np.zeros(le) # b sizes
for m in range(le):
p[m] = axes[np.argwhere(axes==b_[m])[0,0]][1] # only columns are important
return p
# given example (tranposing array "a" by a given permutation argument
# and finding second permution argument for transposing it back to the original array again)
i = 25
j = 32
k = 11
a = np.random.rand(i,j,k)
a_ = np.shape(a) # initial shape
p1 = [2,0,1] # first permutation argument
b_ = permutation_result(a_,p1) # transposed shape
print(f'shape of transposed array = {b_}')
p2 = permutation_arg(np.transpose(a,(p1)),a_) # second permutation argument
print(f'second permutation argument = {p2}')
# which gives:
# shape of transposed array = [11. 25. 32.]
# second permutation argument = [0. 1. 2.]
Upvotes: 0
Reputation: 566
Using transpose, just follow the order. Your first permutation mapped dimensions as:
0th transformed is 2nd original
1st transformed is 0th original
2nd transformed is 1st original
-------------------
0th original is 1st transformed
1st original is 2nd transformed
2nd original is 0th transformed
a = np.random.rand(25,32,11)
b = a.transpose(2,0,1)
np.all(a == b.transpose(1, 2, 0))
yields true
EDIT:
if you want to automate inverse permutation you can use np.argsort
axes = [2, 0, 1]
b = a.transpose(*axes)
np.all(a == b.transpose(*np.argsort(axes)) # yields true
Upvotes: 1