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

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?

100425 次浏览

正如 在文件中解释的那样:

默认情况下,反转尺寸,否则根据给定的值排列轴。

因此可以传递一个可选参数 axes来定义新的维度顺序。

例如,调换 RGB VGA 像素阵列的前两个维度:

 >>> x = np.ones((480, 640, 3))
>>> np.transpose(x, (1, 0, 2)).shape
(640, 480, 3)

要调换数组,NumPy 只需交换每个轴的形状和步长信息:

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


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

请注意,转置操作将跨距替换为轴0和轴1。这些轴的长度也被交换(在这个例子中,两个长度都是 2)。

不需要复制任何数据就可以实现这一点; NumPy 可以简单地改变它如何查看底层内存来构造新数组。


想象步伐

步长值表示为了到达数组轴的下一个值,必须在内存中传输的字节数。

现在,我们的3D 数组 arr看起来是这样的(带有标记的轴) :

enter image description here

This array is stored in a 连续内存块连续内存块; 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

由于每个整数占用8个字节的内存(我们使用的是 int64 dtype) ,因此每个维度的跨距值是需要跳转的值数量的8倍。例如,要沿轴1移动,需要跳转4个值(32字节) ,要沿轴0移动,需要跳转8个值(64字节)。

当我们写 arr.transpose(1, 0, 2)时,我们交换轴0和轴1:

enter image description here

NumPy 需要做的就是交换轴0和轴1的步长信息(轴2保持不变)。现在我们必须沿着轴1比轴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 给你.

总结 交换()[ i,j,k ] = a [ k,j,i ]

a = np.array( range(24), int).reshape((2,3,4))
a.shape gives (2,3,4)
a.transpose().shape gives (4,3,2)  shape tuple is reversed.

当元组参数被传递时,根据元组对轴进行置换。 比如说

A = np.array (range (24) ,int)

a[i,j,k] equals a.transpose((2,0,1))[k,i,j]

坐标0排在第二位

第一轴位于第三位

轴2故事第一名

of course we need to take care that values in tuple parameter passed to transpose are unique and in range(number of axis)

用 C 表示法,你的数组应该是:

int arr[2][2][4]

它是一个包含2个2D 数组的3D 数组。每个二维数组有2个一维数组,每个一维数组有4个元素。

所以你有三个维度。轴是0,1,2,尺寸是2,2,4。这正是 numpy 处理 N 维数组轴的方式。

所以,arr.transpose((1, 0, 2))会把坐标轴1放在位置0,把坐标轴0放在位置1,把坐标轴2放在位置2。你实际上是在排列轴:

0 -\/-> 0
1 -/\-> 1
2 ----> 2

换句话说,1 -> 0, 0 -> 1, 2 -> 2。目标轴总是有序的,所以您只需要指定源轴。按照以下顺序读出元组: (1, 0, 2)

在这种情况下,您的新数组维度也是 [2][2][4],只是因为轴0和轴1的大小相同(2)。

更有趣的是 (2, 1, 0)的转置,它为您提供了 [4][2][2]的数组。

0 -\ /--> 0
1 --X---> 1
2 -/ \--> 2

换句话说,2 -> 0, 1 -> 1, 0 -> 2。按照以下顺序读出元组: (2, 1, 0)

>>> arr.transpose((2,1,0))
array([[[ 0,  8],
[ 4, 12]],


[[ 1,  9],
[ 5, 13]],


[[ 2, 10],
[ 6, 14]],


[[ 3, 11],
[ 7, 15]]])

你得了 int[4][2][2]

如果所有的维度都是不同大小的,那么您可能会更好地理解,因此您可以看到每个轴的去向。

为什么第一个内部元素是 [0, 8]?因为如果你把你的3D 数组想象成两张纸,08排成一行,一张在一张纸上,另一张在另一张纸上,都在左上角。通过移位 (2, 1, 0),你说你希望纸张到纸张的方向现在沿着纸张从左到右行进,并且从左到右的方向现在从纸张到纸张。你有4个元素从左到右,所以现在你有4张纸。你有两篇论文,所以现在你有两个从左到右的元素。

对于糟糕的 ASCII 艺术,我很抱歉

这个问题和例子似乎来源于韦斯 · 麦金尼(Wes McKinney)的书《 用于数据分析的 Python》。transpose的这个特性在 第4.1章数组转换和交换轴中提到。

对于高维数组,transpose将接受一个轴数元组来排列轴(为了额外的思维弯曲)。

在这里“置换”意味着“重新排列”,所以重新排列轴的顺序。

.transpose(1, 0, 2)中的数字决定了与原始数据相比轴的顺序如何更改。通过使用 .transpose(1, 0, 2),我们的意思是,“改变第一轴与第二。”如果我们使用 .transpose(0, 1, 2),数组将保持不变,因为没有什么可更改的; 它是默认顺序。

书中的例子与 (2, 2, 4)大小的数组是不是很清楚,因为第一和第二轴有相同的大小。所以除了 arr[0, 1]arr[1, 0]行的重新排序之外,最终结果似乎没有改变。

如果我们尝试一个不同的例子,一个三维数组,每个维有不同的大小,重新排列的部分变得更加清楚。

In [2]: x = np.arange(24).reshape(2, 3, 4)


In [3]: x
Out[3]:
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]]])


In [4]: x.transpose(1, 0, 2)
Out[4]:
array([[[ 0,  1,  2,  3],
[12, 13, 14, 15]],


[[ 4,  5,  6,  7],
[16, 17, 18, 19]],


[[ 8,  9, 10, 11],
[20, 21, 22, 23]]])

在这里,原始数组大小是 (2, 3, 4)。我们改变了第一和第二,所以它成为 (3, 2, 4)的大小。如果我们仔细观察重排是如何发生的,数字的数组似乎已经改变了一个特定的模式。使用@罗伯特的纸张类比,如果我们取2个数字块,并将每个数字写在表上,然后从每个表中取一行来构造数组的一维,我们现在有一个3x2x4大小的数组,从最外层到最内层进行计数。

[ 0,  1,  2,  3] \ [12, 13, 14, 15]

[ 4,  5,  6,  7] \ [16, 17, 18, 19]

[ 8,  9, 10, 11] \ [20, 21, 22, 23]

使用不同大小的数组,改变不同的坐标轴,以获得对其工作原理的更好直觉,这可能是一个好主意。

我在 Python for Data Analysis杂志上也看到了 Wes McKinney 写的。

I will show the simplest way of solving this for a 3-dimensional tensor, then describe the general approach that can be used for n-dimensional tensors.

简单的三维张量例子

假设你有(2,2,4)-张量

[[[ 0  1  2  3]
[ 4  5  6  7]]


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

如果我们看一下每个点的坐标,它们是这样的:

[[[ (0,0,0)  (0,0,1)  (0,0,2)  (0,0,3)]
[ (0,1,0)  (0,1,1)  (0,1,2)  (0,1,3)]]


[[ (1,0,0)  (1,0,1) (1,0,2) (0,0,3)]
[ (1,1,0)  (1,1,1) (1,1,2) (0,1,3)]]

Now suppose that the array above is example_array and we want to perform the operation: example_array.transpose(1,2,0)

For the (1,2,0)-transformation, we shuffle the coordinates as follows (note that this particular transformation amounts to a "left-shift":

(0,0,0)  ->  (0,0,0)
(0,0,1)  ->  (0,1,0)
(0,0,2)  ->  (0,2,0)
(0,0,3)  ->  (0,3,0)
(0,1,0)  ->  (1,0,0)
(0,1,1)  ->  (1,1,0)
(0,1,2)  ->  (1,2,0)
(0,1,3)  ->  (1,3,0)
(1,0,0)  ->  (0,0,1)
(1,0,1)  ->  (0,1,1)
(1,0,2)  ->  (0,2,1)
(0,0,3)  ->  (0,3,0)
(1,1,0)  ->  (1,0,1)
(1,1,1)  ->  (1,1,1)
(1,1,2)  ->  (1,2,1)
(0,1,3)  ->  (1,3,0)

现在,对于每个原始值,将其放入结果矩阵中的移位坐标中。

例如,值 10在原始矩阵中有坐标 (1, 0, 2),在结果矩阵中有坐标 (0, 2, 1)。它被放置在子矩阵第三行的第一个2d 张量子矩阵中,在该行的第二列中。

因此,得到的矩阵是:

array([[[ 0,  8],
[ 1,  9],
[ 2, 10],
[ 3, 11]],


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

General n-dimensional tensor approach

For n-dimensional tensors, the algorithm is the same. Consider all of the coordinates of a single value in the original matrix. Shuffle the axes for that individual coordinate. Place the value into the resulting, shuffled coordinates in the result matrix. Repeat for all of the remaining values.