1.5.2. Numpy 数组及运算#
Numpy 导入
在Python中使用第三方包时,均需在代码起始行导入包,如下所示。
1# as np表示导入后名称为np,后续可使用np代替全称numpy
2import numpy as np
其中NumPy中生成随机数的Random模块常用函数如表1-1所示:
函数 |
描述 |
|---|---|
np.random.random |
生成0到1之间的随机数 |
np.random.uniform |
生成均匀分布的随机数 |
np.random.randn |
生成标准正态的随机数 |
np.random.randint |
生成随机的整数 |
np.random.normal |
生成正态分布 |
np.random.shuffle |
随机打乱顺序 |
np.random.seed |
设置随机数种子 |
random_sample |
生成随机的浮点数 |
数组
调用NumPy中的array函数可生成NumPy数组。如传递一个Python列表作为参数,则返回的NumPy数组就包括Python列表中的所有元素,其中访问NumPy中的元素与访问Python列表中的元素一致,使用lst[n] 方式访问(lst是数组名,n是从0开始的数组索引)。
其中NumPy中数组创建相关常用函数如表1-2所示:
函数 |
描述 |
|---|---|
np.zeros((3,4)) |
创建3×4的元素全为0的数组 |
np.ones((3,4)) |
创建3×4的元素全为1的数组 |
np.empty((2,3)) |
创建2×3的空数组,空数据中的值并不为0,而是未初始化的垃圾值 |
np.zeros_like(ndarr) |
以ndarr相同维度创建元素全为0数组 |
np.ones_like(ndarr) |
以ndarr相同维度创建元素全为1数组 |
np.empty_like(ndarr) |
以ndarr相同维度创建空数组 |
np.eye(5) |
该函数用于创建一个5×5的矩阵,对角线为1,其余为0 |
np.full((3,5), 666) |
创建3×5的元素全为666的数组,666为指定值 |
1import numpy as np
2
3# 创建一个Python列表
4lst1 = [1, 2, 3, 5]
5# 调用NumPy函数array,传入列表,生成一个NumPy数组
6arr1 = np.array(lst1)
7# 查看Python列表内容
8print(lst1)
9# 查看NumPy数组内容,和上面代码显示的数据内容一样
10print(arr1)
11# 查看其类型
12print(type(lst1))
13# 与上行代码比,两者数据相同,但类型不同、存储方式不同
14print(type(arr1))
[1, 2, 3, 5]
[1 2 3 5]
<class 'list'>
<class 'numpy.ndarray'>
通过不同函数,可以创建不同种类的数组,如随机数数组:
1import numpy as np
2
3# 生成3个随机数组成的数组
4arr3 = np.random.random(size=3)
5# 指定相同的随机数种子,会生成相同的一批随机数
6np.random.seed(166)
7arr4 = np.random.random(size=3)
8print(arr4)
9# 随机打乱数组中各元素的顺序
10np.random.shuffle(arr4)
11print(arr4)
[0.29773903 0.82727708 0.76538624]
[0.82727708 0.76538624 0.29773903]
特定值数组(如全0、全1的数组):
1import numpy as np
2
3# 生成的数据全是0
4arr5 = np.zeros([3, ])
5print(arr5)
6# 生成的数据全是1
7arr6 = np.ones([3, ])
8print(arr6)
9# 生成的数据全是指定值666
10arr7 = np.full([3, ], 666)
11print(arr7)
[0. 0. 0.]
[1. 1. 1.]
[666 666 666]
按指定规则递增/递减的数组:
1import numpy as np
2
3# 生成[0,10)的数组,默认步长为1
4print(np.arange(10))
5# 生成[0,10)的数组,默认步长为1
6print(np.arange(0, 10))
7# 生成[1,5)的数组,步长为0.5
8print(np.arange(1, 5, 0.5))
9# 倒序生成(-1,9]的数组,步长为1
10print(np.arange(9, -1, -1))
[0 1 2 3 4 5 6 7 8 9]
[0 1 2 3 4 5 6 7 8 9]
[1. 1.5 2. 2.5 3. 3.5 4. 4.5]
[9 8 7 6 5 4 3 2 1 0]
在指定取值范围内,按指定数量等分的数组:
1import numpy as np
2
3# 生成[1,10]范围内10个线性等分向量(数字)
4print(np.linspace(1, 10, 10))
[ 1. 2. 3. 4. 5. 6. 7. 8. 9. 10.]
同时,还可以将数组的数据保存到文件中,后续可从文件中恢复数组数据。
1import os
2import numpy as np
3
4arr21 = np.random.random([10, ])
5print(arr21)
6fileName = os.path.join("..", "data", 'testData.txt')
7# 将数组中的数据保存到文件中
8np.savetxt(X=arr21, fname=fileName)
9# 从文件中恢复数组, arr22与arr21的数据应相同
10arr22 = np.loadtxt(fileName)
11print(arr22)
[0.24175633 0.90959386 0.43980117 0.76418946 0.32679251 0.40891362
0.38175381 0.91604818 0.8212697 0.16786087]
[0.24175633 0.90959386 0.43980117 0.76418946 0.32679251 0.40891362
0.38175381 0.91604818 0.8212697 0.16786087]
NumPy 的算术运算
维度和元素个数相同的NumPy数组所进行的加减乘除算术运算是指:将每个数组中每个位置的元素进行相应运算后,再放回新数组相应位置的过程,如下所示。
1import numpy as np
2
3arr1 = np.array([1, 2, 3])
4arr2 = np.array([5, 6, 7])
5# 逐元素相加
6print(arr1 + arr2)
7# 逐元素相减
8print(arr1 - arr2)
9# 逐元素相乘
10print(arr1 * arr2)
11# 逐元素相除
12print(arr1 / arr2)
[ 6 8 10]
[-4 -4 -4]
[ 5 12 21]
[0.2 0.33333333 0.42857143]
数组变形
上节生成的是一维数组(即只有一行数据),在深度学习中用得较多的则是多维数组(排成多行多列的成批数据),为方便读者理解,本书将有些多维数组的叫法与数学上的叫法相统一,即一维数组称为向量、二维数组称为矩阵、三维及三维以上数组称为张量,在NumPy中生成多维数组如下所示。
1import numpy as np
2
3# 生成2行3列数组(又称矩阵)
4arr3 = np.array([[1, 2, 3], [6, 7, 8]])
5# 查看形状
6print("arr3 的形状:", arr3.shape)
7# 显示其数据
8print(arr3)
arr3 的形状: (2, 3)
[[1 2 3]
[6 7 8]]
多维数组之间也可以进行算术运算,其要求是参与运算的多维数组形状相同,以矩阵为例,要求矩阵的行数和列数均相同。
1import numpy as np
2
3# 生成2行3列数组(又称矩阵)
4arr3 = np.array([[1, 2, 3], [6, 7, 8]])
5# 生成2行3列数组(又称矩阵)
6arr4 = np.array([[3, 2, 1], [8, 7, 6]])
7# 查看+运算结果,可发现是逐个元素相加
8print("arr3 + arr4=:", arr3 + arr4)
9# 查看*运算结果,可发现是逐个元素相乘
10print("arr3 * arr4=:", arr3 * arr4)
11# 查看*向量后运算结果,可发现是逐个元素相乘
12print("arr3 * 10=:", arr3 * 10)
arr3 + arr4=: [[ 4 4 4]
[14 14 14]]
arr3 * arr4=: [[ 3 4 3]
[48 49 48]]
arr3 * 10=: [[10 20 30]
[60 70 80]]
在生成数组时可将数组中的元素按指定值填充:
1import numpy as np
2
3# 生成3x3矩阵,其数据值全为0
4arr21 = np.zeros([3, 3])
5print(arr21)
6# 与arr21形状一样的矩阵,其数据值全为0
7arr22 = np.zeros_like(arr21)
8print(arr22)
9# 对角线上元素为1,其他元素全为0的3阶单位矩阵
10arr23 = np.eye(3)
11print(arr23)
12# 对角线上元素为1、2、3,其他全为0的3阶对角矩阵
13arr25 = np.diag([1, 2, 3])
14print(arr25)
[[0. 0. 0.]
[0. 0. 0.]
[0. 0. 0.]]
[[0. 0. 0.]
[0. 0. 0.]
[0. 0. 0.]]
[[1. 0. 0.]
[0. 1. 0.]
[0. 0. 1.]]
[[1 0 0]
[0 2 0]
[0 0 3]]
多维数组中元素的获取举例如下:
1import numpy as np
2
3arr26 = np.linspace(1, 25, 25).reshape([5, 5])
4
5# 将一维数组转换成5行5列矩阵
6print(arr26)
7# 在原矩阵中,取[1,4)行与[1,4)列
8print(arr26[0:3, 0:3])
9# 在原矩阵中,取[2,5)行与所有列
10print(arr26[1:4, :])
11arr27 = np.arange(1, 25, dtype=float)
12print(arr27)
13cse1 = np.random.choice(arr27, size=(4, 3))
14
15# 从数组中随机抽取数,并返回4行3列的矩阵
16print(cse1)
17cse2 = np.random.choice(arr27, size=(4, 3), p=arr27 / np.sum(arr27))
18
19# 同上,但指定概率抽数
20
21print(cse2)
[[ 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.]]
[[ 1. 2. 3.]
[ 6. 7. 8.]
[11. 12. 13.]]
[[ 6. 7. 8. 9. 10.]
[11. 12. 13. 14. 15.]
[16. 17. 18. 19. 20.]]
[ 1. 2. 3. 4. 5. 6. 7. 8. 9. 10. 11. 12. 13. 14. 15. 16. 17. 18.
19. 20. 21. 22. 23. 24.]
[[24. 24. 1.]
[18. 10. 10.]
[19. 13. 6.]
[12. 2. 1.]]
[[21. 16. 12.]
[17. 8. 14.]
[18. 15. 18.]
[ 9. 12. 17.]]
Numpy 的点积运算
点积运算在NumPy中用NumPy.dot(A,B) 表示,又称内积,要求A的第2个维度与B的第1个维度相同才能进行点积运算。以矩阵为例,即A的第2个维度(列)必须与B的第1个维度(行)相同时才能进行点积运算,其使用方法如下。
1import numpy as np
2
3arr28 = np.array([[1, 2], [3, 4]])
4arr29 = np.array([[5, 6, 7], [8, 9, 10]])
5arr30 = np.dot(arr28, arr29)
6
7# 点积运算,其运算过程如图1-19所示
8print(arr30)
[[21 24 27]
[47 54 61]]
图 1-19 点积运算示意图#
NumPy 的广播功能
如前所述的数组算术运算中,要求参与运算的数组须具备相同的形状。实际在NumPy中,形状不同的数组之间也可以进行运算,其中形状较小的数组会被扩展成与形状较大数组相同的形状(如行数较少,则将原行的数值复制到新增行;如列数较少,则将原列的数值复制到新增列)后,再进行算术运算,这就是NumPy的广播功能,其扩展示意如图1-20所示,使用方法如下。
1import numpy as np
2
3# 2行2列矩阵
4arr31 = np.array([[1, 2], [3, 4]])
5# 1行2列矩阵
6arr32 = np.array([10, 20])
7print(arr31)
8# arr32会扩展成2行2列,再与arr31相乘
9print(arr31 * arr32)
[[1 2]
[3 4]]
[[10 40]
[30 80]]
图 1-20 数组扩展示意图#