How does NumPy's transpose() method permute the axes of an array?

Frank Hu picture Frank Hu · Aug 16, 2015 · Viewed 53.4k times · Source
In [28]: arr = np.arange(16).reshape((2, 2, 4))

In [29]: arr
Out[29]: 
array([[[ 0,  1,  2,  3],
        [ 4,  5,  6,  7]],

       [[ 8,  9, 10, 11],
        [12, 13, 14, 15]]])


In [32]: arr.transpose((1, 0, 2))
Out[32]: 
array([[[ 0,  1,  2,  3],
        [ 8,  9, 10, 11]],

       [[ 4,  5,  6,  7],
        [12, 13, 14, 15]]])

When we pass a tuple of integers to the transpose() function, what happens?

To be specific, this is a 3D array: how does NumPy transform the array when I pass the tuple of axes (1, 0 ,2)? Can you explain which row or column these integers refer to? And what are axis numbers in the context of NumPy?

Answer

Alex Riley picture Alex Riley · Aug 16, 2015

To transpose an array, NumPy just swaps the shape and stride information for each axis. Here are the strides:

>>> arr.strides
(64, 32, 8)

>>> arr.transpose(1, 0, 2).strides
(32, 64, 8)

Notice that the transpose operation swapped the strides for axis 0 and axis 1. The lengths of these axes were also swapped (both lengths are 2 in this example).

No data needs to be copied for this to happen; NumPy can simply change how it looks at the underlying memory to construct the new array.


Visualising strides

The stride value represents the number of bytes that must be travelled in memory in order to reach the next value of an axis of an array.

Now, our 3D array arr looks this (with labelled axes):

enter image description here

This array is stored in a contiguous block of memory; essentially it is one-dimensional. To interpret it as a 3D object, NumPy must jump over a certain constant number of bytes in order to move along one of the three axes:

enter image description here

Since each integer takes up 8 bytes of memory (we're using the int64 dtype), the stride value for each dimension is 8 times the number of values that we need to jump. For instance, to move along axis 1, four values (32 bytes) are jumped, and to move along axis 0, eight values (64 bytes) need to be jumped.

When we write arr.transpose(1, 0, 2) we are swapping axes 0 and 1. The transposed array looks like this:

enter image description here

All that NumPy needs to do is to swap the stride information for axis 0 and axis 1 (axis 2 is unchanged). Now we must jump further to move along axis 1 than axis 0:

enter image description here

This basic concept works for any permutation of an array's axes. The actual code that handles the transpose is written in C and can be found here.