一、数组基础
导入numpy是,通常给其一个别名“np”,即
import numpy as np
1.1数据类型
(1)整数型数组与浮点型数组
为克服列表的缺点,应该numpy数组只能容纳一种数据类型,以节约内存。
为方便起见,可将numpy数组简单分成整数型数组与浮点型数组。
注意,使用print输出numpy数组后,元素之间没有逗号,这有两个好处,一是可以将之与python列表区分开,二是避免逗号与小数点之间的混淆。
(2)同化定理
一个人的力量是无法改变全体的,在实际操作中要注意:
往整数型数组里插入浮点数,该浮点数会自动被截断为整数
往浮点型数组里面插入整数,该整数会自动升级为浮点数
(3)共同改变定理
整数型数组和浮点型数组相互转换,规范的方法是使用.astype()方法。
除了上述方法,整数型数组和浮点型数组仍然可以相互转换。最常见的是整数型数组在运算过程中升级为浮点数数组。
1.2数组维度
(1)一维数组与二维数组
考虑到深度学习中三维及其以上的数组出现次数少,我们后续主要讲解NumPy 中的一维数组和二维数组,学了一维和二维后,很好类推到三维。
-
不同维度的数组之间,从外形上的本质区别是
一维数组使用1层中括号表示;
二维数组使用2层中括号表示:
三维数组使用3层中括号表示
-
有些函数需要传入数组的形状参数,不同维度数组的形状参数为
一维数组的形状参数形如:x或(x,);
二维数组的形状参数形如:(x,y);
三维数组的形状参数形如:(x,y,z)
-
现在以同一个序列进行举例
当数组有1层中括号,如[123],则其为一维数组,其形状是3或(3,);
当数组有2层中括号,如[[123]],则其为二维数组,其形状是(1,3);
当数组有3层中括号,如[[[123]]],则其为三维数组,其形状是(1,1,3);
同时,可以查看arr,arr1,arr2的形状
(2)不同维度数组之间的转换
一维数组转二维数组,还是二维数组转一维数组,均要使用的是数组的重塑 方法 .reshape( ) ,该方法需要传入重塑后的形状(shape)参数。
这个方法神奇的是,给定了其他维度的数值,剩下一个维度可以填-1,让它 自己去计算。比如把一个 5 行 6 列的矩阵重塑为 3 行 10 列的矩阵,当列的参数 10 告诉它,行的参数直接可以用-1 来替代,它会自己去用 30 除以 10 来计算。
这里给.reshape( )传入的形状参数是(1,-1),正常情况下我们都肯定是(1,10), 这里(1,-1)的含义是:行的参数是 1 行,列的参数-1 自己去除着算吧。
将二维数组降级为一维数组:
二、数组的创建
2.1创建指定数组
当明确知道数组每一个元素的具体数值时,可以使用np.array()函数,将python列表转化为numpy数组
2.2创建递增数组
递增数组使用np.arange()函数进行创建
2.3创建同值数组
需要创建同值数组时,使用np.zeros()函数以及np.ones()函数,
2.4创建随机数组
有时需要创建随机数组,那么可以使用 np.random 系列函数,如示例所示。
均值为 0、标准差为 1
三、数组的索引
3.1访问数字元素
与 Python 列表一致,访问 NumPy 数组元素时使用中括号,索引由 0 开始。
(1)访问变量
(2)访问矩阵
3.2花式索引
上一小节访问单个元素时,向量用 arr1[x],矩阵用 arr2[x,y]。逗号在矩阵里 用于区分行与列,这一小节,逗号新增一个功能,且不会与矩阵里的逗号混淆。
普通索引用一层中括号,花式索引用两层中括号。
(1)向量的花式索引
(2)矩阵的花式索引
3.3访问数组切片
(1)向量的切片
向量与列表切片的操作完全一致,因此本页内容在Python基础中均有涉及。
当明确知道从第x个元素切到第y个元素u如示例所示:
当明确切除数组的开头与结尾,如示例所示:
当明确隔几个元素采样一次时,示例如下:
(2)矩阵的切片
(3)提取矩阵的行
基于矩阵的切片功能,我们可以提取其部分行,如示例所示。
(4)提取矩阵的列
基于矩阵的切片功能,我们可以提取其部分列,如示例所示。
值得注意的是,提取某一个单独的列时,出来的结果是一个向量。其实这么 做只是为了省空间,我们知道,列矩阵必须用两层中括号来存储,而形状为 1000 的向量,自然比形状为(1000,1)的列矩阵更省空间(节约了 1000 对括号)。
如果你真的想要提取一个列矩阵出来,示例如下。
3.4数组切片仅是视图
(1)数组切片仅是视图
与 Python 列表和 Matlab 不同,NumPy 数组的切片仅仅是原数组的一个视 图。换言之,NumPy 切片并不会创建新的变量,示例如下。
习惯 Matlab 的用户可能无法理解,但其实这正是 NumPy 的精妙之处。试想 一下,一个几百万条数据的数组,每次切片时都创建一个新变量,势必造成大量 的内存浪费。因此,NumPy 的切片被设计为原数组的视图是极好的。
深度学习中为节省内存,将多次使用 arr[:] = <表达式> 来替代 arr = <表达式>。
(2)备份切片为新变量
如果真的需要为切片创建新变量(这种情况很稀少),使用 .copy( ) 方法。
3.5 数组赋值仅是绑定
(1)数组赋值仅是绑定
与 NumPy 数组的切片一样,NumPy 数组完整的赋值给另一个数组,也只是 绑定。换言之,NumPy 数组之间的赋值并不会创建新的变量,示例如下。
(2)复制数组为新变量
如果真的需要赋给一个新数组,使用 .copy( ) 方法。
四、数组的变形
4.1 数组的转置
数组的转置方法为 .T,其只对矩阵有效,因此遇到向量要先将其转化为矩阵。
(1)向量的转置
(2)矩阵的转置
行矩阵的转置刚演示了,列矩阵的转置如示例所示。
4.2数组的翻转
数组的翻转方法有两个,一个是上下翻转的 np.flipud( ) ,表示 up-down; 一个是左右翻转的 np.fliplr( ),表示 left-right。其中,向量只能使用 np.flipud( ), 在数学中,向量并不是横着排的,而是竖着排的。
(1)向量的翻转
(2)矩阵的翻转
4.3数组的重塑
想要重塑数组的形状,需要用到 .reshape( ) 方法。
前面说过,给定了其他维度的数值,剩下一个维度可以填-1,让它自己去计 算。比如把一个 5 行 6 列的矩阵重塑为 3 行 10 列的矩阵,当列的参数 10 告诉 它,行的参数直接可以用-1 来替代,它会自己去用 30 除以 10 来计算。
(1)向量的变形
4.4数组的拼接
(1)向量的拼接
两个向量拼接,将得到一个新的加长版向量
(2)矩阵的拼接
两个矩阵可以按不同的维度进行拼接,但拼接时必须注意维度的吻合。
最后要说明的是,向量和矩阵不能进行拼接,必须先把向量升级为矩阵。
4.5数组的分裂
(1)向量的分裂
向量分裂,将得到若干个更短的向量
np.split( )函数中,给出的第二个参数[2,8]表示在索引[2]和索引[8]的位置截断。
(2)矩阵的分裂
矩阵的分裂同样可以按不同的维度进行,分裂出来的均为矩阵。
五、数组的运算
5.1数组与系数之间的运算
5.2数组与数组之间的运算
同维度数组间的运算即对应元素之间的运算,这里仅以矩阵为例,向量与向量的操作与之相同。
5.3广播
5.2 是同形状数组之间的逐元素运算,本节讲解不同形状的数组之间的运算。 本课件仅讨论二维数组之内的情况,不同形状的数组之间的运算有以下规则:
⚫ 如果是向量与矩阵之间做运算,向量自动升级为行矩阵;
⚫ 如果某矩阵是行矩阵或列矩阵,则其被广播,以适配另一个矩阵的形状。
(1)向量被广播
当一个形状为(x,y)的矩阵与一个向量做运算时,要求该向量的形状必须为 y, 运算时向量会自动升级成形状为(1,y)的行矩阵,该形状为(1,y)的行矩阵再自动被 广播为形状为(x,y)的矩阵,这样就与另一个矩阵的形状适配了。
(2)列矩阵被广播
当一个形状为(x,y)的矩阵与一个列矩阵做运算时,要求该列矩阵的形状必须为(x,1),该形状为(x,1)的列矩阵再自动被广播为形状为(x,y)的矩阵,这样就与另 一个矩阵的形状适配了。
(3)行矩阵与列矩阵同时被广播
当一个形状为(1,y)的行矩阵与一个形状为(x,1) 的列矩阵做运算时,这俩矩阵 都会被自动广播为形状为(x,y)的矩阵,这样就互相适配了。
六、数组的函数
6.1 矩阵乘积
⚫ 第五章中的乘法都是“逐元素相乘”,这里介绍线性代数中的矩阵乘积, 本节只需要使用 np.dot( ) 函数。
⚫ 当矩阵乘积中混有向量时,根据需求,其可充当行矩阵,也可充当列矩阵, 但混有向量时输出结果必为向量。
(1)向量与向量的乘积
设两个向量的形状按前后顺序分别是 5 以及 5 。从矩阵乘法的角度,有 (1,5)*(5,1) = (1,1),因此输出的应该是形状为 1 的向量。
(2)向量与矩阵的乘积
设向量的形状是 5,矩阵的形状是 (5,3) 。从矩阵乘法的角度,有 (1,5)(5,3) = (1,3),因此输出的应该是形状为 3 的向量。
(3)矩阵与向量的乘积
设矩阵的形状是 (3,5) ,向量的形状是 5。从矩阵乘法的角度,有 (3,5)*(5,1) = (3,1),因此输出的应该是形状为 3 的向量。
(4)矩阵与矩阵的乘积
设两个矩阵的形状按前后顺序分别是 (5,2) 以及 (2,8) 。从矩阵乘法的角度, 有(5,2)*(2,8) = (5,8) ,因此输出的应该是形状为 (5,8) 的矩阵。
6.2 数学函数
NumPy 设计了很多数学函数,这里列举其中最重要、最常见的几个
6.3 聚合函数
聚合很有用,这里用矩阵演示。向量与之一致,但没有 axis 参数。以下在注 释中介绍了 6 个最重要的聚合函数,其用法完全一致,仅演示其中 3 个。
⚫ 当 axis=0 时,最终结果与每一行的元素个数一致; 当 axis=1 时,最终结果与每一列的元素个数一致。
⚫ 考虑到大型数组难免有缺失值,以上聚合函数碰到缺失值时会报错,因此 出现了聚合函数的安全版本,即计算时忽略缺失值:np.nansum( )、 np.nanprod( ) 、np.nanmean( )、np.nanstd( )、np.nanmax( )、np.nanmin( )。
七、布尔型数组
除了整数型数组和浮点型数组,还有一种有用的数组类型——布尔型数组。
7.1 创建布尔型数组
由于 NumPy 的主要数据类型是整数型数组或浮点型数组,因此布尔型数组 的产生离不开:大于、大于等于=、等于==、不等号!=、小于<、小于等于<=。
首先,我们将数组与系数作比较,以产生布尔型数组,示例如下。
其次,我们将同维数组作比较,以产生布尔型数组,示例如下。
最后,还可以同时比较多个条件。Python 基础里,同时检查多个条件使用的 与、或、非是 and、or、not。但 NumPy 中使用的与、或、非是 & 、 | 、 ~ 。
7.2 布尔型数组中 True 的数量
有三个关于 Ture 数量的有用函数,分别是 np.sum( )、np.any( )、np.all( )。 np.sum( )函数:统计布尔型数组里 True 的个数。示例如下。
在 In [3]里,np.abs(arr) < 1 可以替换为 (arr>-1) & (arr<1) 。此外,最终统计 的数量为 6814,其概率近似为 0.6827,这符合统计学中的 3σ 准则。
np.any( )函数:只要布尔型数组里含有一个及其以上的 True,就返回 True。
np.all( )函数:当布尔型数组里全是 True 时,才返回 True,示例如下。
7.3 布尔型数组作为掩码
若一个普通数组和一个布尔型数组的维度相同,可以将布尔型数组作为普通 数组的掩码,这样可以对普通数组中的元素作筛选。给出两个示例。 第一个示例,筛选出数组中大于、等于或小于某个数字的元素。
第二个示例,筛选出数组逐元素比较的结果。
7.4 满足条件的元素所在位置
现在我们来思考一种情况:假设一个很长的数组,我想知道满足某个条件的 元素们所在的索引位置,此时使用 np.where( )函数。