- 基于深度学习的python速通(一)
- 基于深度学习的python速通(三)
- 基于深度学习的python速通(二)
数组基础
导入Numpy时,通常给其一个别名,即import numpy as np
数据类型
整数型数组与浮点型数组
为克服列表的缺点,一个Numpy数组只容纳一种数据类型,以节约内存。方便起见,可将Numpy数组简单分为整数型数组与浮点型数组。
1 2 3 4 5 6 7 8
| import numpy as np
arr1 = np.array([1, 2, 3])
arr2 = np.array([1.0, 2.0, 3.0])
print(arr1.dtype) print(arr2.dtype)
|
注意到,使用print输出Numpy数组后,元素之间没有逗号,这有两个好处:
- 可以与python列表区分开
- 避免逗号与小数点混淆
同化定理
- 往整数型数组里插入浮点数,该浮点数会自动被截断为整数
- 往浮点型数组里插入整数,该整数会自动被转换为浮点数
1 2 3 4 5 6 7 8 9 10 11 12 13
| import numpy as np
arr1 = np.array([1, 2, 3])
arr2 = np.array([1.0, 2.0, 3.0])
arr1[0] = 5.5 print(arr1)
arr2[0] = 100 print(arr2) >(5 2 3) >(100.0 2.0 3.0)
|
共同改变定理
同化定理说明整数型数组和浮点型数组之间的界限十分严格,那么如何将这两组数据类型的数组互相转化?
- 整数型数组转换为浮点型数组:使用
astype方法
- 浮点型数组转换为整数型数组:使用
astype方法
1 2 3 4 5 6 7 8 9 10 11 12 13
| import numpy as np
arr1 = np.array([1, 2, 3])
arr2 = np.array([1.0, 2.0, 3.0])
arr1 = arr1.astype(float) print(arr1)
arr2 = arr2.astype(int) print(arr2) >(1 2 3) >(1.0 2.0 3.0)
|
除上述方法,只要阿玛尼组共同改变定理,整数型数组和浮点型数组仍然可以互相转化,最常见的是整数型数组在运算过程中升级为浮点型数组,这在深度学习中非常常见。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| import numpy as np
arr = np.array([1,2,3]) print(arr + 0.0) print(arr * 1.0) >(1.0 2.0 3.0) >(1.0 2.0 3.0)
print(arr/1) >(1.0 2.0 3.0)
int_arr = np.array([1,2,3]) float_arr = np.array([1.0,2.0,3.0]) print(int_arr + float_arr) >(2.0 4.0 6.0)
|
整数型数组很好升级,但浮点型数组在运算过程中一般不会降级
数组维度
一维数组与二维数组
考虑到深度学习中三维及其以上数组出现次数较少,后续主要学习Numpy中的一维数组和二维数组,一二维数组可以类推三维数组
- 不同维度数组之间,从外形上的本质区别是
- 一维数组使用1层中括号
- 二维数组使用2层中括号
- 三维数组使用3层中括号
- 有些函数需要传入数组的形状参数,不同维度数组的形状参数为
- 一维数组:(n,)
- 二维数组:(n,m)
- 三维数组:(n,m,k)
- 现在以同一个序列进行举例
- 当数组有1层中括号,如[1 2 3],则其为一维数组,其形状是3或(3,)
- 当数组有两层中括号,如[[1 2 3]],则其为二维数组,其形状是(1,3)(一行三列)
- 当数组有三层中括号,如[[[1 2 3]]],则其为三维数组,其形状是(1,1,3)(一个1x1的矩阵,每个元素是一个长度为3的向量)
1 2 3 4 5 6 7 8 9
| arr1 = np.ones((3,)) arr2 = np.ones((1,3)) arr3 = np.ones((1,1,3)) print(arr1.shape) print(arr2.shape) print(arr3.shape) >(3,) >(1, 3) >(1, 1, 3)
|
不同维度数组之间的转换
一维数组转二维数组ï¼还是二维数组转一维数组,均要使用数组的重塑方法reshape,该方法需èæ传入重塑后的形状参数
这个方法给定其他维度的数值,剩下的一个维度可以填-1,让Numpy自动计算该维度的数值
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| import numpy as np
arr1 = np.array([1,2,3]) arr2 = arr1.reshape((1,3)) print(arr2) >(1 2 3) >([[1 2 3]])
arr3 = np.arange(10).reshape(2,5) arr4 = arr3.reshape(-1) print(arr3) print(arr4) >[[0 2 3 4 ] [5 6 7 8 9]] >[0 1 2 3 4 5 6 7 8 9]
|
数组的创建
创建指定数组
当明确知道数组的每一个元素时,可以使用np.array()方法将Python列表转化为Numpy数组
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| import numpy as np
arr1 = np.array([1,2,3]) print(arr1)
arr2 = np.array([[1,2,3]]) print(arr2)
arr3 = np.array([[1],[2],[3]]) print(arr3)
arr4 = np.array([[1,2,3],[4,5,6]]) >[1 2 3] >([[1 2 3]]) >([[1] [2] [3]]) >([[1 2 3] [4 5 6]])
|
创建递增数组
递增数组使用np.arange()方法,该方法需要传入数组的长度
1 2 3 4
| import numpy as np arr = np.arange(1,21,2) print(arr) >(1 3 5 7 9 11 13 15 17 19)
|
##创建同值数组
需要创建同值数组时,使用np.ones()或np.zeros()方法,该方法需要传入数组的形状参数
1 2 3 4 5 6 7 8 9 10 11
| import numpy as np
arr1 = np.ones((2,3)) print(arr1)
arr2 = np.zeros((2,3)) print(arr2) >([[1. 1. 1.] [1. 1. 1.]]) >([[0. 0. 0.] [0. 0. 0.]])
|
注意:为避免插入浮点数时被截断,.ones()和.zeros()方法默认创建的数组类型是float64,若需要创建int类型的数组,需要指定dtype参数
创建随机数组
创建随机数组,可以使用np.random.rand()方法,该方法需要传入数组的形状参数
1 2 3 4 5
| import numpy as np arr = np.random.rand(2,3) print(arr) >([[0.5488135 0.71518937 0.60276338] [0.54488318 0.4236548 0.64589411]])
|
np.random.rand()方法创建的随机数组,元素值在[0,1)之间,若需要创建其他范围的随机数组,需要进行缩放或平移
1 2 3 4 5 6
| import numpy as np arr = (100-60)*np.random.random((3,3))+60 print(arr) >([[86.27722064 80.22275727 77.21222227] [82.22222222 82.22222222 82.22222222] [82.22222222 82.22222222 82.22222222]])
|
1 2 3
| arr = np.random.randint(10,100,(1,15)) print(arr) >[[90 66 59 15 58 36 63 59 72 37 79 13 35 63 33]]
|
数组的索引
规定将一维数组称为向量,二维数组成为矩阵
访问数组元素
与Python列表一致,访问Numpy数组元素时使用中括号,索引由0开始
访问向量
1 2 3 4 5 6 7 8
| import numpy as np
arr1 = np.arange(1,10)
print(arr1[1]) print(arr1[-1]) >(2) >(9)
|
访问矩阵
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| import numpy as np
arr2 = np.arange(1,10).reshape((3,3))
print(arr2[1,1]) print(arr2[-1,-1])
arr2[1,1] = 100 print(arr2) >([[1 2 3] [4 100 6] [7 8 9]]) >(5) >(9)
|
花式索引
花式索引(fancy indexing),形如arr[indices],其中indices是一个数组,用于指定需要访问的元素的索引,其与矩阵访问的区别在于矩阵只能访问指定数据的行或列,而花式索引可以访问任意位置的元素
1 2 3 4 5 6 7 8 9 10
| import numpy as np
arr2 = np.arange(1,10).reshape((3,3))
print(arr2) print(arr2[[0,2],[0,2]]) >[[1 2 3] [4 5 6] [7 8 9]] >([1 9])
|
根据以上实例,花式索引也就是用向量来替代普通索引的行列元素,且花式索引输出的仍然是一个向量
| 索引方式 |
向量 |
矩阵 |
| 普通索引 |
arr1[i] |
arr2[i,j] |
| 花式索引 |
arr1[[indices]] |
arr2[[indices1,indices2]] |
访问数组切片
向量的切片
向量与列表切片的操作完全一致
[{"url":"https://lstyimgbed.cn/PicGo/Snipaste_2025-09-17_18-09-33.png","alt":"","title":""}]
索引负责其指向区域的右侧一个单元格
当明确知道从第x给元素切到第y个元素时
1 2 3 4 5 6 7 8 9 10
| import numpy as np arr1 = np.arange(10) print(arr1) print(arr1[1:4]) print(arr1[ :4]) print(arr1[4: ]) >[0 1 2 3 4 5 6 7 8 9] >[1 2 3] >[0 1 2 3] >[4 5 6 7 8 9]
|
当明确切除数组的开头与结尾
1 2 3 4
| print(arr1[2:-2]) print(arr1[ :-2]) >[2 3 4 5 6 7] >[0 1 2 3 4 5 6 7]
|
当明确隔几个元素采样一次时
1 2
| print(arr1[1:8:2]) >[1 3 5 7]
|
矩阵的切片
矩阵的切片与向量的切片操作一致,只是需要在方括号中添加逗号,逗号前的索引表示行,逗号后的索引表示列
1 2 3 4 5 6 7 8 9 10 11
| import numpy as np
arr2 = np.arange(1,10).reshape((3,3))
print(arr2) print(arr2[1:3,1:3]) >[[1 2 3] [4 5 6] [7 8 9]] >([[5 6] [8 9]])
|
基于矩阵的切片功能,可以提取矩阵的部分行
1 2 3 4 5 6 7 8 9 10 11
| arr3 = np.arange(1,21).reshape(4,5) print(arr3) print(arr3[2,:]) print(arr3[1:3,:]) >[[ 1 2 3 4 5] [ 6 7 8 9 10] [11 12 13 14 15] [16 17 18 19 20]] >[11 12 13 14 15] >[[ 6 7 8 9 10] [11 12 13 14 15]]
|
考虑代码的简介,当提取矩阵的部分行时,只需要在方括号中添加行索引即可,不需要添加逗号
1 2
| print(arr3[2,:]) print(arr3[3])
|
注意提取列的时候不能简写
提取矩阵的列
1 2 3 4 5 6 7 8 9 10 11 12 13
| arr4 = np.arange(1,21).reshape(4,5) print(arr4) print(arr4[:,2]) print(arr4[:,1:3]) >[[ 1 2 3 4 5] [ 6 7 8 9 10] [11 12 13 14 15] [16 17 18 19 20]] >[ 3 8 13 18] >[[ 2 3] [ 7 8] [12 13] [17 18]]
|
值得注意的是,当提取某一个单独的列时,出来的结果是一个向量,其实这么做只是为了省空间,我们知道,列矩阵必须用两层中括号来存储,使用向量输出可以大幅减少内存使用
若想提取真正的列矩阵,需要使用reshape方法进行升级再转置
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| arr4 = np.arange(1,16).reshape(3,5) print(arr4) print(arr4[:,2]) print(arr4[:,1:3]) cut = arr4[:,2].reshape(1,3) print(cut.T) >[[ 1 2 3 4 5] [ 6 7 8 9 10] [11 12 13 14 15]] >[ 3 8 13] >[[ 2 3] [ 7 8] [12 13]] >[[ 3] [ 8] [13]]
|
与Python列表不同,NumPy数组的切片仅仅是原数组的一个视图,换言之,NumPy切牌你并不会创建新的变量,而是指向原数组的一个引用,因此,当修改切片时,原数组也会被修改
1 2 3 4 5 6
| import numpy as np arr = np.arange(10) cut = arr[ :3] cut[0] = 100 print(arr) >([100 1 2 3 4 5 6 7 8 9])
|
深度学习中为节省内存,将多次使用arr[:]=<表达式>来替代arr=<表达式>
备份切片为新变量可以使用.copy()方法
1 2 3 4 5 6
| import numpy as np arr = np.arange(10) cut = arr[ :3].copy() cut[0] = 100 print(arr) >([0 1 2 3 4 5 6 7 8 9])
|
数组赋值仅是绑定
与NumPy数组的切片一样,NumPy数组完整的赋值给另一个数组,也只是指向原数组的一个引用,因此,当修改数组时,原数组也会被修改
1 2 3 4 5 6
| import numpy as np arr = np.arange(10) arr2 = arr arr2[0] = 100 print(arr) >([100 1 2 3 4 5 6 7 8 9])
|
若需复制为新数组,方法同数组的切片,使用.copy()方法
数组的变形
数组的转置方法为.T只对矩阵有效,因此遇到向量要先将其转化为矩阵
向量的转置
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| import numpy as np arr1 = np.arange(1,4) arr2 = arr1.reshape(1,-1) arr3 = arr2.T print(arr1) print(arr2) print(arr3) >[1 2 3] >[[1 2 3]] >[[1] [2] [3]]
arr4 = arr1.reshape(-1,1) print(arr4) >[[1] [2] [3]]
|
矩阵的转置
列ç©阵ç转置如下所示
1 2 3 4 5 6 7 8 9
| import numpy as np arr1 = np.arange(1,4).reshape(-1,1) arr2 = arr1.T print(arr1) print(arr2) >[[1] [2] [3]] >[[1 2 3]]
|
数组的翻转
数组的翻转方法有两个,一个是上下翻转np.flipud(),表示up-down翻转,另一个是左右翻转np.fliplr(),表示left-right翻转,其中,向量只能使用np.flipud()方法。
向量的翻转
1 2 3 4 5
| import numpy as np arr1 = np.arange(10) arr_ud = np.flipud(arr1) print(arr_ud) >[9 8 7 6 5 4 3 2 1 0]
|
矩阵的翻转
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| import numpy as np arr1 = np.arange(1,21).reshape(4,5) arr_lr = np.fliplr(arr1) arr_ud = np.flipud(arr1) print(arr1) print(arr_lr) print(arr_ud) >[[ 1 2 3 4 5] [ 6 7 8 9 10] [11 12 13 14 15] [16 17 18 19 20]] >[[ 5 4 3 2 1] [10 9 8 7 6] [15 14 13 12 11] [20 19 18 17 16]] >[[16 17 18 19 20] [11 12 13 14 15] [ 6 7 8 9 10] [ 1 2 3 4 5]]
|
矩阵的重塑
矩阵的重塑方法为.reshape(),其中,-1表示自动计算维度,例如,将一个向量升级为列矩阵时,可以使用arr.reshape(-1,1),将一个向量升级为行矩阵时,可以使用arr.reshape(1,-1)。
数组的拼接
向量的拼接
两个向量拼接,将得到一个新的加长版向量
1 2 3 4 5 6
| import numpy as np arr1 = np.array([1,2,3]) arr2 = np.array([4,5,6]) arr3 = np.concatenate([arr1,arr2]) print(arr3) >[1 2 3 4 5 6]
|
矩阵的拼接
两个矩阵可以按照不同的维度进行拼接,但拼接式必须注意维度的吻合
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| import numpy as np arr1 = np.array([[1,2,3],[4,5,6]]) arr2 = np.array([[7,8,9],[10,11,12]])
arr3 = np.concatenate([arr1,arr2]) print(arr3)
arr4 = np.concatenate([arr1,arr2],axis=1) print(arr4) >[[ 1 2 3] [ 4 5 6] [ 7 8 9] [10 11 12]] >[[ 1 2 3 7 8 9] [ 4 5 6 10 11 12]]
|
数组的分裂
向量的分裂,将得到若干个更短的向量
1 2 3 4 5 6 7 8 9 10 11 12
| import numpy as np arr = np.arange(10,100,10)
arr1,arr2,arr3 = np.split(arr,[2,8]) print(arr) print(arr1) print(arr2) print(arr3) >[10 20 30 40 50 60 70 80 90] >[10 20] >[30 40 50 60 70 80] >[90]
|
np.split()函数中,给出的第二个参数[2,8]表示再索引[2]和索引[8]的位置截断
矩阵的分裂
矩阵分裂同样可以以不同维度进行
1 2 3 4 5 6 7 8 9
| import numpy as np
arr = np.array(1,0).reshape(2,4)
arr1,arr2 = np.split(arr,[1]) print(arr1,'\n\n',arr2)
arr1,arr2,arr3 = np.split(arr,[1,3],axis = 1) print(arr1,'\n\n',arr2,'\n\n',arr3)
|
数组的运算
python基础中,常用的运算符如表所示,Numpy的运算符与之相同
数组与系数的运算
以矩阵为例,向量与系数的操作与python相同
1 2 3 4 5 6 7 8 9
| import numpy as np arr = np.arange(1,9).reshanpe(2,4) print(arr + 10) print(arr - 10) print(arr * 10) print(arr / 10) print(arr ** 10) print(arr // 10) print(arr % 10)
|
数组与数组之间的运算
同维度数组间的运算即对应元素之间的运算,这里仅以矩阵为例,向量与向量之间的操作相同
1 2 3 4 5 6 7 8 9 10
| import numpy as np arr1 = np.arange(-1,-9,-1).reshape(2,4) arr2 = arr1 print(arr1 + arr2) print(arr1 - arr2) print(arr1 * arr2) print(arr1 / arr2) print(arr1 ** arr2) print(arr1 // arr2) print(arr1 % arr2)
|
乘法是遵循对应元素相乘的,可以称之为“逐元素乘积”,线性代数中矩阵乘法的实现用对应函数
广播
在二维数组中,不同形状的数组之间的运算有以下规则
- 如果是向量与矩阵之间做运算,向量自动升级为行矩阵
- 如果某矩阵是行矩阵或列矩阵,则其被广播,以适配另一个矩阵的形状
向量被广播
当一个形状为(x,y) 的矩阵与一个向量做运算时,要求该向量的形状必须为y,运算时向量会自动升级为形状为(1,y)的行矩阵,该å½¢式为(1,y)的行矩阵再自动被广播为形状(x,y)的矩阵,这样就与另一个矩阵的形状适配了
1 2 3 4 5 6 7 8
| import numpy as np
arr1 = np.array([-100,0,100]) print(arr1)
arr2 = np.random.random((10,3)) print(arr2) print(arr1 * arr2)
|
列矩阵被广播
当一个形状为(x,y)的矩阵与一个列矩阵做运算时,要求该列矩阵的形状必须为(x,1)的矩阵再自动被广播为形状(x,y)的矩阵,这样就与另一个矩阵的形状适配了
1 2 3 4 5 6 7 8 9
| import numpy as np
arr1 = np.arange(3).reshape(3,1) print(arr1)
arr2 = np.ones((3,5)) print(arr2)
print(arr1 * arr2)
|
行矩阵与列矩阵同时被广播
当一个形状为(1,y)的行矩阵与形状为(x,1)的列矩阵做运算时,这两矩阵都会被自动广播为形状(x,y)的矩阵,以互相适配
1 2 3 4 5 6
| arr1 = np.arange(3)
arr2 = np.arange(3).reshape(3,1)
print(arr1 * arr2)
|
数组的函数
矩阵乘积
- 第五章中的乘法都是“逐元素相乘”,这里是线性代数中的矩阵乘积,只需要使用
np.dot()函数
- 当矩阵乘积中混有向量时,根据需求,其可充当行矩阵,也可充当列矩阵,但混有向量时输出结果必为向量
向量与向量的乘积
设两个向量的形状按前后顺序分别为(1,5)、5,1,从矩阵乘法的角度,有(1,5)x(5,1)=(1,1),因此输出的应该是形状为(1,1)的向量
1 2 3 4 5 6
| import numpy as np
arr1 = np.arange(5) arr2 = np.arange(5)
print(np.dot(arr1,arr2))
|
向量与矩阵的乘积
设向量的形状是(1,5),矩阵的形状是(5,3),有(1,5)x(5,3)=(1,3),因此输出的也应该是形状为(1,3)的向量
1 2 3 4 5 6
| import numpy as np
arr1 = np.arange(5) arr2 = np.arange(15).reshape(5,3)
print(np.dot(arr1,arr2))
|
向量与矩阵的乘积
设向量的形状是(1,5),矩阵的形状是(5,3),有(1,5)x(5,3)=(1,3),因此输出的也应该是形状为(1,3)的向量
1 2 3 4 5 6
| import numpy as np
arr1 = np.arange(5) arr2 = np.arange(15).reshape(5,3)
print(np.dot(arr1,arr2))
|
向量与矩阵的乘积
设向量的形状是(1,5),矩阵的形状是(5,3),有(1,5)x(5,3)=(1,3),因此输出的也应该是形状为(1,3)的向量
1 2 3 4 5 6
| import numpy as np
arr1 = np.arange(5) arr2 = np.arange(15).reshape(5,3)
print(np.dot(arr1,arr2))
|
向量与矩阵的乘积
设向量的形状是(5,1),矩阵的形状是(3,5),有(5,1)x(3,5)=(3,1),因此输出的也应该是形状为(3,1)的向量
1 2 3 4 5 6
| import numpy as np
arr1 = np.arange(5) arr2 = np.arange(15).reshape(3,5)
print(np.dot(arr1,arr2))
|
矩阵与矩阵的乘积
设两个矩阵的形状按前后顺序分别是(5,2)以及(2,8),有(5,2)x(2,8)=(5,8)
1 2 3 4
| import numpy as np arr1 = np.arange(10).reshape(5,2) arr2 = np.arange(16).reshape(2,8) print(np.dot(arr1,arr2))
|
数学函数
Numpy设计了许多数学函数,此处仅列举深度学习中常用的几个
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
| import numpy as np
arr_v = np.array([-10,0,10]) abs_v = np.abs(arr_v) print("原数组是",arr_v) print("绝对值是",abs_v)
theta = np.arange(3) * np.pi/2 sin_v = np.sin(theta) cos_v = np.cos(theta) tan_v = np.tan(theta) print("原数组是",theta) print("正弦函数",sin_v) print("余弦函数",cos_v) print("正切函数",tan_v)
x = np.array([1,10,100,1000]) print("x = ",x) print("ln(x) = ",np.log(x)) print("log2(x) = ",np.log(x)/np.log(2)) print("log10(x) = ",np.log(x)/np.log(10))
x = np.arange(1,4) print("x = ",x) print("e^x",np.exp(x)) print("2^x",2**x) print("10^x",10**x)
|