文章目录
- 1. 什么是转置
- 2. 转置操作
- 2.1 transpose
- 2.2 ndarray.T
- 2.3 moveaxis
- 2.4 rollaxis
- 2.5 permute_dims
- 2.6 swapaxes
- 2.7 matrix_transpose
1. 什么是转置
在线性代数中,矩阵转置是指将矩阵的行和列进行互换,即原矩阵的第
i
i
i 行、第
j
j
j 列元素,在转置后变为第
j
j
j 行、第
i
i
i 列元素。给定一个
m
×
n
m \times n
m×n 的矩阵
A
A
A,其转置矩阵
A
T
A^T
AT 是一个
n
×
m
n \times m
n×m 的矩阵,满足:
(
A
T
)
i
j
=
A
j
i
(A^T)_{ij} = A_{ji}
(AT)ij=Aji
示例, 原矩阵
A
A
A:
A
=
[
1
2
3
4
5
6
]
(
2
×
3
)
A = \begin{bmatrix} 1 & 2 & 3 \\ 4 & 5 & 6 \end{bmatrix} \quad (2 \times 3)
A=[142536](2×3)
转置矩阵
A
T
A^T
AT 为:
A
T
=
[
1
4
2
5
3
6
]
(
3
×
2
)
A^T = \begin{bmatrix} 1 & 4 \\ 2 & 5 \\ 3 & 6 \end{bmatrix} \quad (3 \times 2)
AT=
123456
(3×2)
具体表现为:
- 原矩阵的第 1 行
→
转置矩阵的第 1 列 - 原矩阵的第 2 行
→
转置矩阵的第 2 列 - 以此类推
在高维数组中,转置的操作更加灵活,可以:
- 完全反转所有轴的顺序(默认行为)。
- 自定义轴的排列顺序(如指定轴的交换顺序)。
在机器学习中转置常用于:
- 调整图像数据的通道顺序。
- 将时间序列数据从 (序列长度, 特征数) 转为 (特征数, 序列长度)。
- 神经网络中的权重矩阵维度匹配。
- 卷积操作中的滤波器方向调整。
2. 转置操作
2.1 transpose
transpose()
(转置):通过轴的重新排列改变数组的维度结构(默认返回视图)。
函数、方法定义:
# 函数
def transpose(a, axes=None)
# 方法
def transpose(self, axes: None | _ShapeLike, /) -> Self: ...
参数说明:
a
:输入数组(支持任意维度)。axes
:指定新轴的排列顺序。
不同维度的行为说明:
数组维度 | 默认行为(无 axes 参数) | 说明 |
---|---|---|
1-D | 返回原数组的视图 | 无实际转置操作,仍是 1D 数组,仅改变数组的 strides 属性) |
2-D | 标准矩阵转置 | 行列互换 |
n-D | 反转所有轴的顺序 | 原轴顺序 (0,1,2) 变为 (2,1,0) ) |
示例 1 ,转置二维数组:
# 二维数组
arr_2d = np.array([[1, 2, 3],
[4, 5, 6]])
# 转置
# 函数调用
transposed_2 = np.transpose(arr_2d)
print(transposed_2)
# 输出:
#[[1 4]
# [2 5]
# [3 6]]
# 方法调用
transposed_1 = arr_2d.transpose()
print(transposed_1)
注意:转置后内存共享,修改转置后的元素会影响原数组:
# 修改转置矩阵元素
transposed_2[1, 1] = 99 # 第二行第二列修改为 5-> 99
print(arr_2d)
# 原数组被修改
# [[ 1 2 3]
# [ 4 99 6]]
示例 2 ,三维数组:
arr_3d = np.arange(24).reshape(2, 3, 4) # 形状 (2, 3, 4)
print(arr_3d)
# [[[ 0 1 2 3]
# [ 4 5 6 7]
# [ 8 9 10 11]]
#
# [[12 13 14 15]
# [16 17 18 19]
# [20 21 22 23]]]
# 转置
transposed = np.transpose(arr_3d)
print(transposed.shape) # 形状(4,3,2)
print(transposed)
# [[[ 0 12]
# [ 4 16]
# [ 8 20]]
#
# [[ 1 13]
# [ 5 17]
# [ 9 21]]
#
# [[ 2 14]
# [ 6 18]
# [10 22]]
#
# [[ 3 15]
# [ 7 19]
# [11 23]]]
转置过程的核心是轴顺序的变化,每个元素的索引按新轴顺序重组,例如三维数组的转置公式为:
(
A
T
)
i
j
k
=
n
e
w
A
k
j
i
(A^T)_{ijk} = newA_{kji}
(AT)ijk=newAkji
示例:
A[0,0,0]
->newA[0,0,0]
A[0,0,1]
->newA[1,0,0]
A[1,2,3]
->newA[3,2,1]
- 依次映射所有元素
比如,案例中的三维数据,A[1,2,3]
索引即第二层第三行第四列的元素为 23
,转置后放在 newA[3,2,1]
即第四层第三行第二列,可以看下转置后的输出,也是 23
。
示例 3 ,有一个形状为 (2, 3, 4)
的三维数组,轴的顺序为 (0, 1, 2)
,那么 axes
参数是包含三个整数的元组,然后可以设置不同轴顺序:
axes 参数 | 转置后形状 | 转置规则(原轴顺序 → 新轴顺序) | 示例元素映射(原位置 → 新位置) |
---|---|---|---|
默认(None ) | (4, 3, 2) | (0, 1, 2) → (2, 1, 0) | arr[1, 2, 3] → new[3, 2, 1] |
(0, 1, 2) | (2, 3, 4) | 无变化 | arr[1, 0, 0] → new[1, 0, 0] |
(1, 0, 2) | (3, 2, 4) | 交换块(0轴)和行(1轴) | arr[1, 2, 3] → new[2, 1, 3] |
(0, 2, 1) | (2, 4, 3) | 交换行(1轴)和列(2轴) | arr[0, 1, 2] → new[0, 2, 1] |
(2, 0, 1) | (4, 2, 3) | 列→块→行 | arr[1, 0, 0] → new[0, 1, 0] |
(2, 1, 0) | (4, 3, 2) | 反转所有轴(等价默认) | arr[0, 2, 3] → new[3, 2, 0] |
(1, 2, 0) | (3, 4, 2) | 行→列→块 | arr[1, 0, 0] → new[0, 0, 1] |
代码示例:
arr = np.arange(24).reshape(2, 3, 4) # shape (4, 3, 2)
print(arr)
# [[[ 0 1 2 3]
# [ 4 5 6 7]
# [ 8 9 10 11]]
#
# [[12 13 14 15]
# [16 17 18 19]
# [20 21 22 23]]]
transposed = np.transpose(arr, axes=(1, 0, 2))
print(transposed) # shape (3, 4, 2)
# [[[ 0 1 2 3]
# [12 13 14 15]]
#
# [[ 4 5 6 7]
# [16 17 18 19]]
#
# [[ 8 9 10 11]
# [20 21 22 23]]]
扩展,在计算机视觉领域,图像通常以多维数组存储,比如彩色图的两种格式:
HWC
(Height
,Width
,Channels
):即(高度, 宽度, 通道)CHW
(Channels
,Height
,Width
):即(通道, 高度, 宽度)
在模型训练和预测的过程中,往往会涉及到格式转换,比如 OpenCV
读取图像的格式为 HWC
,PyTorch
要求的格式是 CHW
,需要在数据内容不变的情况下,整存储顺序,适配不同框架的计算需求。
一个常用的代码片如下:
# 读取图片(HWC格式)
img_rgb = cv2.cvtColor(img_bgr, cv2.COLOR_BGR2RGB)
# 转换为 CHW 格式(使用 copy ,防止转置后的视图与原数组共享内存,避免意外的修改。)
img_chw = np.transpose(img_rgb.copy(), (2, 0, 1))
2.2 ndarray.T
NumPy
还提供了一个是一个数组对象的转置属性,即 arr.T
,等价于调用 np.transpose(arr)
,默认反转数组的所有轴。
示例:
arr_3d = np.arange(24).reshape(2, 3, 4)
print("原形状:", arr_3d.shape) # (2, 3, 4)
transposed_3d = arr_3d.T
print("转置后形状:", transposed_3d.shape) # (4, 3, 2)
2.3 moveaxis
numpy.moveaxis
:将指定轴移动到目标位置,其他轴按原有顺序自动排列。
函数定义:
def moveaxis(a, source, destination)
参数说明:
a
:输入的多维数组。source
:要移动的轴的原始位置。destination
:移动后的目标位置。
注意事项:
- 是
transpose
函数的一个特例。 - 返回原数组的视图
- 支持同时移动多个轴到不同目标位置
- 目标位置按以下规则处理:
- 正索引:从左到右(
0
开始)。 - 负索引:从右到左(
-1
表示最后一个位置)。
- 正索引:从左到右(
示例 1 ,移动 0
轴到末尾,形状由 (3,4,5)
变为 (4,5,3)
,元素 a[x,y,k]
依次重新排入到 a[y,k,x]
的索引位置:
x = np.arange(60).reshape(3, 4, 5) # shape (3,4,5)
print(x)
# [[[ 0 1 2 3 4]
# [ 5 6 7 8 9]
# [10 11 12 13 14]
# [15 16 17 18 19]]
#
# [[20 21 22 23 24]
# [25 26 27 28 29]
# [30 31 32 33 34]
# [35 36 37 38 39]]
#
# [[40 41 42 43 44]
# [45 46 47 48 49]
# [50 51 52 53 54]
# [55 56 57 58 59]]]
# 移动轴 0 到末尾
y = np.moveaxis(x, 0, -1) # shape (4,5,3)
print(y)
# [[[ 0 20 40]
# [ 1 21 41]
# [ 2 22 42]
# [ 3 23 43]
# [ 4 24 44]]
#
# [[ 5 25 45]
# [ 6 26 46]
# [ 7 27 47]
# [ 8 28 48]
# [ 9 29 49]]
#
# [[10 30 50]
# [11 31 51]
# [12 32 52]
# [13 33 53]
# [14 34 54]]
#
# [[15 35 55]
# [16 36 56]
# [17 37 57]
# [18 38 58]
# [19 39 59]]]
同时移动多个轴时,原位置和目标位置都是数组,且需要保持依次对应关系。示例 2 ,同时移动轴 0
和轴 1
到新位置,即 0
移动到末尾,1
移动到倒数第二位置:
x = np.arange(60).reshape(3, 4, 5) # shape (3,4,5)
y = np.moveaxis(x, [0, 1],
[-1, -2]) # shape (5,4,3)
print(y)
# [[[ 0 20 40]
# [ 5 25 45]
# [10 30 50]
# [15 35 55]]
#
# [[ 1 21 41]
# [ 6 26 46]
# [11 31 51]
# [16 36 56]]
#
# [[ 2 22 42]
# [ 7 27 47]
# [12 32 52]
# [17 37 57]]
#
# [[ 3 23 43]
# [ 8 28 48]
# [13 33 53]
# [18 38 58]]
#
# [[ 4 24 44]
# [ 9 29 49]
# [14 34 54]
# [19 39 59]]]
2.4 rollaxis
numpy.rollaxis()
:将指定轴滚动到目标位置,其他轴的相对顺序保持不变。
函数定义:
def rollaxis(a, axis, start=0)
注意事项: 仅为了向后兼容性考虑,建议优先使用moveaxis
,所有这里就不演示了。
2.5 permute_dims
numpy.permute_dims()
:通过轴的重新排列改变数组的维度结构(默认返回视图)。
函数定义:
def rollaxis(a, axis, start=0)
提示: permute_dims
是 transpose
的别名函数,功能完全等效。
2.6 swapaxes
swapaxes()
:交换数组的两个指定轴,调整数据的维度顺序而不改变数据本身。
函数、方法定义:
# 函数
def swapaxes(a, axis1, axis2):
# 方法
def swapaxes(
self,
axis1: SupportsIndex,
axis2: SupportsIndex,
) -> ndarray[_Shape, _DType_co]: ...
参数说明:
a
:输入的多维数组。axis1
:第一个待交换的轴索引。axis2
:第二个待交换的轴索引。
在之前我们学过转置函数(transpose
),可以控制所有轴的顺序,而 swapaxes
可以看成它的一个特例,是一种只交换两个轴的操作。
示例 1 ,二维数组交换交换 0
轴和 1
轴:
import numpy as np
x = np.array([[1, 2], [3, 4]]) # shape (2, 2)
y = np.swapaxes(x, 0, 1) # 交换轴 0 和轴 1
print(y)
# 输出:
# [[1 3]
# [2 4]]
示例 2 ,三维数组交换交换 0
轴和 2
轴,轴顺序由(0,1,2
)变为(2,1,0
),元素 a[x,y,k]
依次重新排入到 a[k,y,x]
的索引位置:
x = np.array([[[0, 1], [2, 3]],
[[4, 5], [6, 7]]]) # shape (2, 2, 2)
y = np.swapaxes(x, 0, 2) # 交换轴 0(外层)和轴 2(内层)
print(y)
# 输出:
# [[[0, 4],
# [2, 6]],
# [[1, 5],
# [3, 7]]]
2.7 matrix_transpose
numpy.matrix_transpose()
:专为转置矩阵或批量矩阵设计的函数,仅交换输入数组的最后两个维度,其他维度保持不变。适用于遵循 Array API
标准的操作。
函数定义:
def matrix_transpose(x, /)
参数说明:
x
:输入的类数组对象,形状为(..., M, N)
,其中...
表示任意数量的前置维度,最后两个维度M
和N
构成矩阵。
返回值:
out
:ndarray
类型,形状为(..., N, M)
。每个最后两维的矩阵M×N
被转置为N×M
,前置维度完全保留。
注意事项:
- 仅转置最后两个维度,无论输入数组维度多高,只交换最后两个轴。
- 适合处理堆叠的矩阵(如多个样本、多个通道的数据)。
- 遵循
Array API
标准,行为与其他框架(如PyTorch
、TensorFlow
)一致。
示例 1 ,二维矩阵转置:
x = [[1, 2], [3, 4]] # 形状 (2, 2)
y = np.matrix_transpose(x)
print(y)
# [[1, 3],
# [2, 4]]
示例 2 ,三维矩阵转置时,每个矩阵独立转置,前置维度(第一维)保持不变:
x = [[[1, 2], [3, 4]], [[5, 6], [7, 8]]] # 形状 (2, 2, 2)
y = np.matrix_transpose(x)
print(y)
# [[[1, 3], # 第一个矩阵转置
# [2, 4]],
# [[5, 7], # 第二个矩阵转置
# [6, 8]]]