NumPy的transpose()方法如何排列数组的轴?


81
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]]])

当我们将整数元组传递给transpose()函数时,会发生什么?

具体来说,这是一个3D数组:当我传递轴的元组时,NumPy如何变换该数组(1, 0 ,2)?您能解释这些整数指的是哪行或哪一列?在NumPy的上下文中,轴号是什么?



2
0是第一个轴,1是第二个轴,是2第三个轴,依此类推...在您的示例中,axes用于transpose提供您希望它们排列的新顺序的参数:首先是第二个,然后是第一个,然后是第三个。
2015年

在3d显示中,有块,行和列。您的转置已切换块和行的顺序,而列则保持不变。原来是第一个块的第二行的内容将成为第二个块的第一行。
hpaulj 2015年

Answers:


183

为了转置数组,NumPy只是交换每个轴的形状和步幅信息。这是大步前进:

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

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

请注意,转置操作将步幅交换为轴0和轴1。这些轴的长度也被交换了(2在此示例中,这两个长度都相同)。

无需复制任何数据即可完成此操作;NumPy可以简单地更改其查看基础内存的方式以构造新数组。


可视化步幅

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

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

在此处输入图片说明

这个数组存储在一个连续的内存块中; 本质上是一维的。要将其解释为3D对象,NumPy必须跳过一定的恒定字节数才能沿三个轴之一移动:

在此处输入图片说明

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

当我们写时,arr.transpose(1, 0, 2)我们将交换轴0和1。转置后的数组如下所示:

在此处输入图片说明

NumPy所需要做的就是交换轴0和轴1的步幅信息(轴2不变)。现在,我们必须跳得更远,才能沿着轴1而不是轴0:

在此处输入图片说明

这个基本概念适用于数组轴的任何排列。处理转置的实际代码是用C编写的,可以在这里找到。


6
@Alex:谢谢!这些数字是使用draw.io制作的
Alex Riley

6

文档中所述

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

因此,您可以传递一个可选参数来axes定义新的尺寸顺序。

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

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

1
嗨,谢谢你的回答。但是,我仍然无法理解这个问题,如您所见,arr的形状是(2,2,4),而arr.transpose(1,0,2)也是(2,2,4)。这是一个3维数组,当我通过(1,0,2)时如何变换数组,您能解释一下1,0,2指的是哪一行或哪一列吗?轴数是多少?
胡锦涛

1
@FrankHu在3d空间中可视化,因此x,y轴旋转就是这里发生的情况。(1,0,2)从(0,1,2)移置,因此前两个轴被切换。0是轴的索引号。说,x,y,z映射到0,1,2
CodeFarmer

5

用C表示法,您的数组将是:

int arr[2][2][4]

这是具有2个2D阵列的3D阵列。这些2D数组中的每个都有2个1D数组,这些1D数组中的每个都有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张纸。而且您有2篇论文,所以现在您有2个元素从左到右。

对不起,可怕的ASCII艺术。 ¯\_(ツ)_/¯


我认为您给的元组transpose()不是数学排列或其他任何东西,对吗?字面上只是说“使轴现在处于这些位置”的指令?例如,对于.transpose(p, q, r, s)你说“把轴线p为第0个,q为第1,r为第12和s作为第三”?还是看到了另一种b = a.transpose(axes)方式b.shape == tuple(a.shape[i] for i in axes)
蒂姆(Tim)

用ASCII艺术交换轴的想法阐明了我的理解。非常感谢
K_inverse

0

看来问题和示例出自Wes McKinney的《Python for Data Analysis》一书。第4.1章中transpose提到了此功能。转置数组和交换轴

对于更高维的数组,transpose将接受轴编号的元组以对轴进行置换(以增加思维的弯曲度)。

这里的“置换”是指“重新排列”,因此要重新排列轴的顺序。

中的数字.transpose(1, 0, 2)确定与原始轴相比如何更改轴的顺序。通过使用.transpose(1, 0, 2),我们的意思是“将第二把斧头改为第二把斧头”。如果使用.transpose(0, 1, 2),则数组将保持不变,因为没有任何更改。这是默认顺序。

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

如果我们尝试使用3维数组(每个维具有不同大小)的不同示例,则重排部分将变得更加清晰。

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)的尺寸变大了。如果我们仔细观察,看看重新排列是如何发生的;数字数组似乎已在特定模式下发生了变化。使用@RobertB的书面类比,如果我们要取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]

最好使用不同大小的数组,并更改不同的轴以更好地了解其工作原理。


-3

总结a.transpose()[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.

当是元组参数时,将根据元组对轴进行排列。例如

一个= np.array(range(24),int).reshape((2,3,4))

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

轴0排名第二

轴1排名第三

轴2故事第一名

当然,我们需要注意传递给转置的元组参数中的值是唯一的,并且在范围(轴数)中


您尚未解决OP的问题,即使用指定的轴进行转置时会发生什么。
罗伯特B

指定轴后,对问题的回答增加了。
拉古·拉姆
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.