经过前几章的学习,我们已经掌握了NumPy中最常用的一些功能,比如如何创建NumPy Array,如何在不同维度的矩阵中进行索引,还有一些常用的数学函数,本章是NumPy入门教程的最后一章,我们就来学习一下NumPy中的一些高级的操作函数。
Transposing Array 数组变位
我们可以使用NumPy的transpose函数将矩阵各个维度进行对换:
m1 = np.arange(6).reshape((2, 3))
print(m1)
[[0 1 2]
[3 4 5]]
print(np.transpose(m1)) # 将矩阵的维度进行对换
[[0 3]
[1 4]
[2 5]]
m2 = np.ones((1, 2, 3))
print(np.transpose(m2, (1, 0, 2)).shape) # 将原数组的维度(0, 1, 2)换成(1, 0, 2)
m3 = np.ones((2, 3, 4, 5))
print(np.transpose(m3).shape) # 对换m3矩阵所有的维度(0, 1, 2, 3)换成(3, 2, 1, 0)
m4 = np.arange(24).reshape(2, 3, 4)
print(m4)
[[[ 0 1 2 3]
[ 4 5 6 7]
[ 8 9 10 11]]
[[12 13 14 15]
[16 17 18 19]
[20 21 22 23]]]
m5 = m4.transpose((2, 0, 1)) # 维度对换:(2, 3, 4) => (4, 2, 3)
print(m5)
[[[ 0 4 8]
[12 16 20]]
[[ 1 5 9]
[13 17 21]]
[[ 2 6 10]
[14 18 22]]
[[ 3 7 11]
[15 19 23]]]
m6 = m4.swapaxes(0, 1) # 置换特定的维度:(2, 3, 4) => (3, 2, 4)
print(m6)
Stacking Arrays 合并
接下来我们来学习一些如何合并数组。
array1 = np.full((1, 5), 1.0)
array2 = np.full((1, 5), 2.0)
stacked_array = np.vstack((array1, array2)) # 竖直合并序列中的数组(行方向)
print(stacked_array)
[[1. 1. 1. 1. 1.]
[2. 2. 2. 2. 2.]]
matrix1 = np.full((3, 2), 1.0)
matrix2 = np.full((3, 2), 2.0)
stacked_matrix = np.hstack((matrix1, matrix2)) # 水平合并序列中的数组(列方向)
print(stacked_matrix)
[[1. 1. 2. 2.]
[1. 1. 2. 2.]
[1. 1. 2. 2.]]
我们还能使用concatenate对多个矩阵或序列进行合并,通过自定义axis的位置,则能更方便地合并矩阵:
cmatrix1 = np.concatenate((matrix1, matrix2), axis = 0) # 和vstack相同
cmatrix2 = np.concatenate((matrix1, matrix2), axis = 1) # 和hstack相同
print(cmatrix1)
[[1. 1.]
[1. 1.]
[1. 1.]
[2. 2.]
[2. 2.]
[2. 2.]]
print(cmatrix2)
[[1. 1. 2. 2.]
[1. 1. 2. 2.]
[1. 1. 2. 2.]]
matrix1 = np.full((3, 3), 1)
matrix2 = np.full((3, 3), 2)
matrix3 = np.stack((matrix1, matrix2)) # 沿着新轴将矩阵合并,要保持两个矩阵形状一致
print(matrix3)
[[[1 1 1]
[1 1 1]
[1 1 1]]
[[2 2 2]
[2 2 2]
[2 2 2]]]
Splitting Array 分割
NumPy还能使用相似的功能分割数组:
big_matrix = np.arange(36).reshape(9, 4)
print(big_matrix)
[[ 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]]
m1, m2, m3 = np.vsplit(big_matrix, 3) # 将一个数组垂直分割成多个子数组(按行)
print(m1)
[[ 0 1 2 3]
[ 4 5 6 7]
[ 8 9 10 11]]
print(m2)
[[12 13 14 15]
[16 17 18 19]
[20 21 22 23]]
print(m3)
[[24 25 26 27]
[28 29 30 31]
[32 33 34 35]]
m4, m5 = np.hsplit(big_matrix, 2) # 将一个数组水平分割为多个子数组(按列)
print(m4)
[[ 0 1]
[ 4 5]
[ 8 9]
[12 13]
[16 17]
[20 21]
[24 25]
[28 29]
[32 33]]
print(m5)
[[ 2 3]
[ 6 7]
[10 11]
[14 15]
[18 19]
[22 23]
[26 27]
[30 31]
[34 35]]
Tile
Tile函数可以重复某个数组以构成一个新的数组:
m1 = np.arange(4)
print(m1)
print()
m2 = np.tile(m1, (4, 1)) # 重复4个m2矩阵,并将它们按行合并
print(m2)
[[0 1 2 3]
[0 1 2 3]
[0 1 2 3]
[0 1 2 3]]
m3 = np.tile(m1, (4, 2)) # 重复8个矩阵,4个按行合并,4个按列合并
print(m3)
[[0 1 2 3 0 1 2 3]
[0 1 2 3 0 1 2 3]
[0 1 2 3 0 1 2 3]
[0 1 2 3 0 1 2 3]]
重要机制
最后我们学习一下NumPy中重要的机制,虽然这个比较枯燥,但是也是需要了解的。
Broadcasting 广播
广播原则的前提:两个数组必须可以转化成维度大小一模一样才能进行运算。
规则1:如果两个数组的维度不同,那么小维度数组的形状将会在最左边补1
m1 = np.arange(4).reshape(1, 1, 4)
print(m1)
[[[0 1 2 3]]]
print(m1 + [10, 10, 20, 20]) # 等于:m1 + [[[10, 10, 20, 20]]](形状(1,1,4))
[[[10 11 22 23]]]
规则2:如果两个数组的形状在任何一个维度上都不匹配,那么数组的形状则会沿着维度为1扩展,以匹配另一个数组的形状。
m2 = np.arange(6).reshape(2, 3)
print(m2)
[[0 1 2]
[3 4 5]]
print(m2 + [[10], [20]]) # 等于: m2 + [[10, 10, 10], [20, 20, 20]]
[[10 11 12]
[23 24 25]]
print(m2 + [10, 20, 30]) # 规则1:[[10,20,30]] => 规则2:[[10,20,30],[10,20,30]]
[[10 21 32]
[13 24 35]]
print(m2 + 100) # 与之相同的逻辑: m2 + [[100, 100, 100], [100, 100, 100]]
[[100 101 102]
[103 104 105]]
m3 = np.array([[1,2,3], [4,5,6], [7,8,9], [10, 11, 12]])
[[ 1 2 3]
[ 4 5 6]
[ 7 8 9]
[10 11 12]]
m4 = np.array([1, 0, 1])
[1 0 1]
m5 = m3 + m4 # 使用广播将 m4 加到 m3 的每一行上
print(m5)
[[ 2 2 4]
[ 5 5 7]
[ 8 8 10]
[11 11 13]]
规则3:如果两个数组的形状在任何一个维度上都不匹配,并且没有任何一个维度为1,那么就会引起异常。
try:
m1 = np.arange(4).reshape(1, 1, 4)
m1 + [33, 44] # 规则3会引发异常
except ValueError as e:
print(e)
Upcasting
将不同数据类型的数组进行运算时,运算结果会自动将数据类型转变为更为精确的数据类型:
m1 = np.arange(0, 5, dtype=np.int8)
print(m1.dtype, m1) # uint8
m2 = m1 + np.array([5, 6, 7, 8, 9], dtype=np.int16)
print(m2.dtype, m2) # int16
m3 = m1 + 1.5
print(m3.dtype, m3) # float64
Homework
将下面两个形状为(2, 4)的矩阵沿着第一个维度(axis=0)合并,然后将结果按列分割成两个形状为(4,2)的矩阵,最后将其中任何一个矩阵按着列(第二个维度)重复一遍,得到一个(4,4)的矩阵。
m1 = np.arange(8).reshape(2, 4)
m2 = np.arange(8).reshape(2, 4)
答案:
m3 = np.vstack((m1, m2))
print(m3)
print('********')
m4, m5 = np.hsplit(m3, 2)
print(m4)
print('********')
m6 = np.tile(m4, (1, 2))
print(m6)