How to transpose axes back after .transpose?

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

Answers (2)

hamflow
hamflow

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

Dominik Ficek
Dominik Ficek

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

Related Questions