NumPy库的基本使用
1. NumPy基础
全称:Numeric Python
- NumPy是Python的科学计算基础库
- NumPy底层是C语言编写的,可以对数组进行高效的数学运算
- NumPy的ndarray对象可以用来构建多维数组
- NumPy能够执行傅里叶变换与重塑多维数组形状
- NumPy提供了线性代数,以及随机数生成的内置函数
1.1 为什么需要使用NumPy库?
Python里并没有数组变量类型,常用的list列表类型可以存储不同数据类型的值,这就导致我们需要为每一个元素都单独存储它的数据类型,造成了内存的浪费,当我们需要管理相同类型的值且需要对这些值进行更细节的操作时,Python的列表类型远远达不到我们的要求,且Python的计算速度也太慢。
而NumPy库为Python加上了关键的数组变量类型,每一个数组的所有元素必须是相同的数据类型,且提供了全方面的细节操作,底层用C语言编写,计算速度也很快。
1.2 NumPy ndarray对象
我们在导入NumPy时,通常给其一个别名:np
,即import numpy as np
NumPy中的数组对象称为ndarray。
可以使用array()
函数创建一个NumPy ndarray对象。
注意:数组输出[ ]中没有逗号,列表有逗号,注意区分
import numpy as np arr = np.array([1, 2, 3, 4, 5]) print(arr) # [1 2 3 4 5] print(type(arr)) # <class 'numpy.ndarray'>
可以将列表、元组或任意类型数组的对象传递给array()
方法,然后它将会被转化为ndarray。
arr = np.array((1, 2, 3, 4, 5)) print(arr) # [1 2 3 4 5]
1.3 数据类型
理论上来说,数组有好多数据类型,但这里我们只讲解最常用的两种数据类型:整数型数组和浮点型数组,其余类型相同用法。
arr1 = np.array([1, 2, 3]) # 元素都是整数,则为整数型数组 print(arr1.dtype) # int64 print(arr1) # [1 2 3] arr2 = np.array([1.0, 2, 3]) # 元素存在浮点数,则为浮点型数组 print(arr2.dtype) # float64 print(arr2) # [1. 2. 3.]
1.3.1 数据类型同化原理(个人无法改变集体)
注意:
- 当整数型数组已经创建完毕,往里插入/修改为浮点数,该浮点数会自动同化为整数(数据截断)
- 当浮点型数组已经创建完毕,往里插入/修改为整数,该整数会自动同化为浮点数(数据升级)
arr1 = np.array([1, 2, 3]) # 元素都是整数,则为整数型数组 arr1[1] = 4.1 print(arr1) # [1 4 3] arr2 = np.array([1.0, 2, 3]) # 元素存在浮点数,则为浮点型数组 arr2[2] = 4 print(arr2) # [1. 2. 4.]
1.3.2 数据类型转化(共同改变定理)
将整个数组的数据类型共同改变,规范化的方式是使用ndarray.astype(想改成的数据类型)
。
arr1 = np.array([1, 2, 3]) # 元素都是整数,则为整数型数组 print(arr1) # [1 2 3] print(arr1.astype(float)) # [1. 2. 3.] arr2 = np.array([1.0, 2, 3]) # 元素存在浮点数,则为浮点型数组 print(arr2) # [1. 2. 3.] print(arr2.astype(int)) # [1 2 3]
只要符合共同改变定理,即可以全部转化成功,所以可以使用数组的共同计算来改变数据类型,最常见的是整数型数组在运算过程中升级为浮点型数组。
浮点型数组在运算过程中一般是不会降级的,所以这里重点考虑整数型数组的升级即可。
arr1 = np.array([1, 2, 3]) # 元素都是整数,则为整数型数组 print(arr1) # [1 2 3] # 整数型数组和浮点数做运算(+ - *) print(arr1 + 1.0) # [2. 3. 4.] # 整数型数组遇到除法运算,即便是除以整数也会变为浮点数(/) print(arr1 / 1) # [1. 2. 3.] # 整数型数组和浮点型数组做运算(+ - * /) arr2 = np.array([1.0, 2.0, 3.0]) print(arr1 + arr2) # [2. 4. 6.]
1.4 数组维度
维度数 = 中括号层数
不同维度的数组之间,从外形上的本质区别是几维数组就有几层中括号。
1.4.1 形状:shape
不同数组有不同的形状表示:
- 一维数组(向量):
x
或(x,)
- 如:
[1, 2, 3].shape = (3,)
- 如:
- 二维数组(矩阵):
(x, y)
- 如:
[[1 2 3]].shape = (1, 3)
- 如:
- 三维数组:
(x, y, z)
- 如:
[[[1 2 3]]].shape = (1, 1, 3)
- 如:
查询数组形状语法:ndarray.shape
1.4.2 维度转换:reshape
数组的重塑语法:ndarray.reshape(shape)
(shape是重塑后的形状参数)
用于调整数组形状,重塑后并不会产生新的数组,只是产生新的视图(类似指针)。
该方法在填写形状值时,给定了其它维度的值,剩下一个维度可以填-1,让它自己去计算。
当把多维数组降为一维数组时,直接reshape(-1)
即可
arr1 = np.arange(10) # 创建包含0到10的数组,不包括10 print(arr1) # [0 1 2 3 4 5 6 7 8 9] # 升维 arr2 = arr1.reshape(2, -1) # 自动计算成(2,5) print(arr2) ''' [[0 1 2 3 4] [5 6 7 8 9]] ''' # 降维 arr3 = arr2.reshape(-1) print(arr3) # [0 1 2 3 4 5 6 7 8 9]
1.5 NumPy其它属性操作
-
ndarray.dtype
:返回数组的数据类型。 -
ndarray.itemsize
:返回数组中每个元素的大小(即每个元素占用的字节数)。 -
ndarray.shape
:返回数组的形状。shape
属性的返回值是一个由数组维度构成的元组,如:2行3列的二维数组返回(2,3),该属性也可以用来调整数组维度大小。
-
ndarray.size
:同np.size(ndarray)
,返回数组中的所有底层标量元素的个数。 -
ndarray.ndim
:返回数组的维数,如二维数组返回2。 -
ndarray.flags
:返回数组的内存信息,如:ndarray数组的存储方式,以及是否是其它数组的副本等。 -
ndarray.fill(?)
:把某数填充到数组中
import numpy as np arr = np.array([[1, 2, 3, 4, 5],[6, 7, 8, 9, 10]]) print(arr.dtype) # int64 print(arr.itemsize) # 8 print(arr.size) # 10 print(arr.ndim) # 2 print(arr.shape) # (2, 5) print(arr.flags) ''' C_CONTIGUOUS : True F_CONTIGUOUS : False OWNDATA : True WRITEABLE : True ALIGNED : True WRITEBACKIFCOPY : False ''' arr.fill(0) print(arr) ''' [[0 0 0 0 0] [0 0 0 0 0]] '''
2. 数组初始化
2.1 创建指定数组
一般来说,当明确知道数组每一个元素的具体数值时,可以使用np.array()
函数创建一个NumPy ndarray对象。
向量是最节省内存的数组结构,列矩阵是最消耗内存的数组结构。
# 创建一维数组——向量 arr1 = np.array([1, 2, 3]) print(arr1) # [1 2 3] # 创建二维数组——行矩阵 arr2 = np.array([[1, 2, 3]]) print(arr2) # [[1 2 3]] # 创建二维数组——列矩阵 arr3 = np.array([[1], [2], [3]]) print(arr3) ''' [[1] [2] [3]] ''' # 创建二维数组——矩阵 arr4 = np.array([[1, 2, 3], [4, 5, 6]]) print(arr4) ''' [[1 2 3] [4 5 6]] '''
2.2 创建同值数组
语法:np.zeros(shape)
语法:np.ones(shape)
这两个函数一般用来创建元素均为0或1的数组,同时还可以指定数组形状,需要注意的是,两个函数里的数据类型默认为浮点型,并不是整数,这是为了避免用户后期插入进去的浮点数被截断导致数据损失。
arr = np.zeros(3) print(arr) # [0. 0. 0.] arr = np.zeros((3,2)) print(arr) ''' [[0. 0.] [0. 0.] [0. 0.]] ''' brr = np.ones((4,3)) print(brr) ''' [[1.+0.j 1.+0.j 1.+0.j] [1.+0.j 1.+0.j 1.+0.j] [1.+0.j 1.+0.j 1.+0.j] [1.+0.j 1.+0.j 1.+0.j]] '''
除了创建元素0或1的数组外,该方法还可以用来创建其它同值数组,只需要满足共同改变定理。
arr = 12 * np.ones(3) print(arr) # [12. 12. 12.]
2.3 创建随机数组
使用np.random
系列函数可以创建随机数组。
- 0-1均匀分布的浮点型随机数组:
np.random.random(shape)
arr = np.random.random(5) print(arr) # [0.34733891 0.57971267 0.80269101 0.76184404 0.21501071]
该方法很灵活,若想创建50到100范围内均匀分布的3*3随机数组:(100-50) * np.random.random((3,3)) + 50
即:波动值 * np.random.random((3,3)) + 下限
- 整数型随机数组:
np.random.randint(start, end, shape)
# 创建10到100之间形状为(1,15)的随机矩阵 A = np.random.randint(10, 100, (1, 15)) print(A) # [[23 96 59 86 92 71 64 19 19 22 18 76 10 63 12]]
- 服从正态分布的随机数组:
np.random.normal(均值, 标准差, (形状))
还有种更简单的写法:np.random.randn(shape)
A = np.random.normal(0, 1, (2,3)) print(A) ''' [[-1.02794824 -1.00740807 0.57600102] [ 0.90604223 0.72598196 -0.3247751 ]] ''' A = np.random.randn(2,3) print(A) ''' [[-0.85803819 1.55360033 -0.95891918] [-0.2942526 -0.28620573 -0.56165943]] '''
2.4 创建区间数组:arange
可以使用arange()
来创建给定数值范围的数组,也叫递增数组。
语法:np.arange(start, end, step)
- start:起始值,默认为0(可不写)
- end:终止值,不包含该值
- step:步长,默认为1(可不写)
数据类型默认为整数,需要浮点型的可以使用np.arange(7.0)
或1.0 * np.arange(7)
来进行创建,或定义dtype = float
。
arr = np.arange(7) print(arr) # [0 1 2 3 4 5 6] arr = np.arange(1, 9, 2, dtype=float) print(arr) # [1. 3. 5. 7.]
2.5 创建等差数组:linspace
表示在指定的数值区间内,返回均匀间隔的一维等差数列,默认均分50份。
语法:np.linspace(start, end, num=50, endpoint=True)
- num:表示均分多少份(可不写)
- endpoint:若为True,则数列包含end,反之不包含(可不写)
arr = np.linspace(1, 10, 5) print(arr) # [ 1. 3.25 5.5 7.75 10. ]
2.6 创建等比数组:logspace
语法:np.logspace(start, end, num=50, endpoint=True)
arr = np.logspace(0, 1, 5) print(arr) # [ 1. 1.77827941 3.16227766 5.62341325 10. ]
2.7 创建未初始化的数组
对于未初始化的数组,会给他随便赋一个值。
语法:np.empty(shape, dtype)
- shape:指定数组的形状
- dtype:数组元素的数据类型,默认为float(可不写)
arr = np.empty((3,2), dtype=int) print(arr) ''' [[-9223369491628071134 806051871720660] [ 2545226692878 2545226692886] [ 3 29]] '''
3. 索引与切片
在NumPy中,如果想要访问或修改数组中的元素,可以采用索引或切片的方式,这与Python的list列表是相同的。
3.1 普通索引
访问数组元素需要使用数组索引。
NumPy数组中的索引以0开头,与Java等数组不同的是,其索引可以使用负数。
第一个元素索引号:0,最后一个元素索引号可以表示为:-1(正着数从0开始,倒着数从-1开始)
arr = np.array([1, 2, 3, 4]) # 获取第一个元素 print(arr[0]) # 获取最后一个元素 print(arr[-1]) # 将第二个和第三个元素相加 print(arr[1] + arr[2]) ''' 1 4 5 ''' arr = np.array([[1, 2, 3, 4], [5, 6, 7, 8]]) # 获取第一维中的第二个元素 print(arr[0, 1]) # 获取第二维中的第4个元素 print(arr[1, 3]) # 用负索引 print(arr[1, -1]) ''' 2 8 8 '''
访问矩阵也是一样的道理,注意使用普通索引时,索引外面只套一层中括号。
[ [1,2,3], [4,5,6], [7,8,9] ] 取5:arr[1,1] # 5 取第二行所有值:arr[1] # [4,5,6] 取第二列所有制:arr[:,1] # [2,5,8] :表示所有 取第一行的前两个值:arr[0,0:2] # [1,2] 里面可以写切片格式
3.2 花式索引
普通索引用一层中括号,而花式索引用两层中括号。
花式索引更加高效。
# 向量的花式索引 arr1 = np.arange(0, 100, 10) print(arr1) # [ 0 10 20 30 40 50 60 70 80 90] # 花式索引:取第0个和第2个位置的元素,并将其组成向量输出 print(arr1[[0, 2]]) # [ 0 20] # 矩阵的花式索引 arr2 = np.arange(0, 100, 10).reshape(2, -1) print(arr2) ''' [[ 0 10 20 30 40] [50 60 70 80 90]] ''' # 花式索引1:表示先取出第0索引行和第1索引行,再取出第0索引行第1索引列和第1索引行第3索引列的元素 print(arr2[[0, 1], [1, 3]]) # [10 80] # 花式索引2: print(arr2[[0, 1, 0], [1, 2, 3]]) # [10 70 30]
怎么理解:","前的向量表示行元素,后的向量表示列元素,所以两个向量相同位置为一组坐标,按位置找出元素组成新的向量输出打印。
3.3 基本切片
切片方式返回的是数组视图(浅拷贝,类似指针)
NumPy中有两种切片方式。
一种是使用NumPy的内置函数slice()
来创建切片对象,将其传入数组中(不推荐):ndarray[slice(start, end, step)]
arr = np.array(range(10)) print(arr) # [0 1 2 3 4 5 6 7 8 9] print(arr[slice(1, 6, 2)]) # [1 3 5]
一种是直接在ndarray对象上进行冒号切片(推荐):ndarray[start : end : step]
(注意是冒号)
arr = np.array(range(10)) print(arr) # [0 1 2 3 4 5 6 7 8 9] print(arr[1:6:2]) # [1 3 5]
对冒号切片的简单说明:
- 如果仅输入一个参数,则会返回与索引相对应的元素,如:
[3]
返回3 - 如果写这种形式:
[:9]
,则会返回0-8之间的所有数字(左闭右开) - 如果是:
[2:]
,则会返回从2到最后的所有数字 - 如果在两个参数之间:
[2:9]
,则是对两个索引之间进行切片
4. 副本和视图
4.1 副本和视图的区别
副本和数组视图之间的主要区别在于副本是一个新的数组,而视图表示的还是原始数组。
副本拥有数据,对副本所作的任何更改都不会影响原始数组,对原始数组所作的任何更改也不会影响副本。
视图不拥有数据,(类似指针),对视图所作的任何更改都会影响原始数组,对原始数组所作的任何更改也会影响视图。
4.2 副本
副本:arr.copy()
arr = np.array([1, 2, 3, 4, 5]) x = arr.copy() arr[0] = 8 x[-1] = 88 print(arr) # [8 2 3 4 5] print(x) # [ 1 2 3 4 88]
4.3 视图
视图:arr.view()
arr = np.array([1, 2, 3, 4, 5]) x = arr.view() arr[0] = 8 x[-1] = 88 print(arr) # [ 8 2 3 4 88] print(x) # [ 8 2 3 4 88]
4.4 判断数组是数组还是视图
副本拥有数据,而视图不拥有数据。
每个NumPy数组都有一个属性:base
,若该数组有数据,则这个base
属性返回None
。
否则,base
属性将引用原始对象。
arr = np.array([1, 2, 3, 4, 5]) x = arr.copy() y = arr.view() print(x.base) # None print(y.base) # [1 2 3 4 5] print(arr.base) # None
5. 数组的变形
5.1 转置
数组的转置方法.T
,只对矩阵有效,因此遇到向量(一维数组)需要先将其转为矩阵。
# 向量的转置 arr1 = np.arange(3) print(arr1) # [0 1 2] arr2 = arr1.reshape(1,-1) print(arr2) # [[0 1 2]] print(arr2.T) ''' [[0] [1] [2]] ''' # 矩阵的转置 arr3 = np.arange(10).reshape(2, 5) print(arr3) ''' [[0 1 2 3 4] [5 6 7 8 9]] ''' print(arr3.T) ''' [[0 5] [1 6] [2 7] [3 8] [4 9]] '''
5.2 翻转
数组的反转方法有两个:
np.flipud(ndarray)
:表示up-down,上下翻转;np.fliplr(ndarray)
:表示left-right,左右翻转。
注意:向量只能上下翻转,因为向量并不是横着排的,在数学中,它是竖着排的。
# 向量的翻转 arr1 = np.arange(10) print(arr1) # [0 1 2 3 4 5 6 7 8 9] arr1_ud = np.flipud(arr1) print(arr1_ud) # [9 8 7 6 5 4 3 2 1 0] # 矩阵的翻转 arr2 = np.arange(1,21).reshape(4,5) print(arr2) ''' [[ 1 2 3 4 5] [ 6 7 8 9 10] [11 12 13 14 15] [16 17 18 19 20]] ''' arr2_lr = np.fliplr(arr2) # 左右翻转 print(arr2_lr) ''' [[ 5 4 3 2 1] [10 9 8 7 6] [15 14 13 12 11] [20 19 18 17 16]] ''' arr2_ud = np.flipud(arr2) # 上下翻转 print(arr2_ud) ''' [[16 17 18 19 20] [11 12 13 14 15] [ 6 7 8 9 10] [ 1 2 3 4 5]] '''
5.3 重塑
重塑函数:ndarray.reshape()
,可以调整数组形状,重塑后并不会产生新的数组,只是产生新的视图(类似指针)。
# 1. 向量的重塑 arr1 = np.arange(1, 10) print(arr1) # [1 2 3 4 5 6 7 8 9] # 将向量变形为矩阵 arr2 = arr1.reshape(3, 3) print(arr2) ''' [[1 2 3] [4 5 6] [7 8 9]] ''' # 2. 矩阵的重塑 arr3 = np.array([[1, 2, 3], [4, 5, 6]]) print(arr3) ''' [[1 2 3] [4 5 6]] ''' # 将矩阵变形为向量 arr4 = arr3.reshape(6) print(arr4) # [1 2 3 4 5 6] # 将矩阵变形为其它形状矩阵 arr5 = arr3.reshape(1, 6) print(arr5) # [[1 2 3 4 5 6]]
5.4 拼接
两个数组之间可以进行拼接形成一个新的数组。
语法:np.concatenate([ndarray1, ndarray2], axis=0)
- axis:表示按什么方向拼接,默认0表示行方向,1表示列方向
5.4.1 向量的拼接
两个向量的拼接,将得到一个加长版的向量。
a1 = np.array([1,2,3]) a2 = np.array([4,5,6]) a3 = np.concatenate([a1, a2]) print(a3) # [1 2 3 4 5 6]
5.4.2 矩阵的拼接
两个矩阵可以按照不同的维度进行拼接,但是一定注意:拼接时两个矩阵的维度必须吻合。
且向量和矩阵无法拼接,必须先把向量升级为矩阵。
a1 = np.array([[1,2,3], [4,5,6]]) a2 = np.array([[7,8,9], [10,11,12]]) # 按第一个维度(行)拼接 a3 = np.concatenate([a1, a2]) # axis = 0(默认) print(a3) ''' [[ 1 2 3] [ 4 5 6] [ 7 8 9] [10 11 12]] ''' # 按第二个维度(列)拼接 a4 = np.concatenate([a1, a2], axis=1) print(a4) ''' [[ 1 2 3 7 8 9] [ 4 5 6 10 11 12]] '''
5.5 数组的分割
语法:np.split(ndarray, [start, end])
5.5.1 向量的分割
a1 = np.arange(10, 100, 10) print(a1) # [10 20 30 40 50 60 70 80 90] # 分割数组 a2, a3, a4 = np.split(a1, [2, 5]) print(a2) # [10 20] print(a3) # [30 40 50] print(a4) # [60 70 80 90]
5.5.2 矩阵的分割
矩阵的分割可以根据参数axis
按照不同的维度进行,分割出来的子元素都是矩阵。
a1 = np.arange(1, 9).reshape(2, 4) print(a1) ''' [[1 2 3 4] [5 6 7 8]] ''' # 按照第一个维度(行)分割 a2, a3 = np.split(a1, [1]) print(a2) # [[1 2 3 4]] print(a3) # [[5 6 7 8]] # 按照第二个维度(列)分割 a4, a5, a6 = np.split(a1, [1, 3], axis=1) print(a4) ''' [[1] [5]] ''' print(a5) ''' [[2 3] [6 7]] ''' print(a6) ''' [[4] [8]] '''
6. 数组的运算
6.1 数组与系数的运算
NumPy的运算符与Python相同:+、-、*、/、**、//、%、()
arr = np.arange(1, 9).reshape(2, 4) print(arr) ''' [[1 2 3 4] [5 6 7 8]] ''' # 加法 print(arr + 10) ''' [[11 12 13 14] [15 16 17 18]] ''' # 减法 print(arr - 10) ''' [[-9 -8 -7 -6] [-5 -4 -3 -2]] ''' # 乘法 print(arr * 10) ''' [[10 20 30 40] [50 60 70 80]] ''' # 除法 print(arr / 10) ''' [[0.1 0.2 0.3 0.4] [0.5 0.6 0.7 0.8]] ''' # 平方 print(arr ** 2) ''' [[ 1 4 9 16] [25 36 49 64]] ''' # 取整 print(arr // 6) ''' [[0 0 0 0] [0 1 1 1]] ''' # 取余 print(arr % 6) ''' [[1 2 3 4] [5 0 1 2]] '''
6.2 数组与数组的运算
相同维度数组之间的运算即对应元素之间的运算。
遵循逐元素计算。
arr1 = np.arange(-1, -9, -1).reshape(2, 4) print(arr1) ''' [[-1 -2 -3 -4] [-5 -6 -7 -8]] ''' arr2 = -arr1 print(arr2) ''' [[ 1 2 3 4] [ 5 6 7 8]] ''' # 加法 print(arr1 + arr2) ''' [[ 0 0 0 0] [ 0 0 0 0]] ''' # 减法 print(arr1 - arr2) ''' [[ -2 -4 -6 -8] [-10 -12 -14 -16]] ''' # 乘法 print(arr1 * arr2) ''' [[ -1 -4 -9 -16] [-25 -36 -49 -64]] ''' # 除法 print(arr1 / arr2) ''' [[ 1. 1. 1. 1.] [ 1. 1. 1. 1.]] ''' # 幂方 print(arr1 ** arr2) ''' [[ -1 4 -27 256] [ -3125 46656 -823543 16777216]] '''
7. 数组的广播
数组可以进行运算。
b = np.array([10,20,30,40]) c = b + 1 print(c) # [11 21 31 41]
如果进行运算的两个数组形状完全相同,它们可以直接做相应的运算。
a = np.array([0.1,0.2,0.3,0.4]) b = np.array([10,20,30,40]) c = a * b print(c) # [ 1. 4. 9. 16.]
b = np.array([10,20,30,40]) c = b + 1 print(c) # [11 21 31 41]
但如果两个形状不同的数组呢?它们之间就不能做算术运算了吗?当然不是!为了保持数组形状相同,NumPy 设计了一种广播机制,这种机制的核心是对形状较小的数组,在横向或纵向上进行一定次数的重复,使其与形状较大的数组拥有相同的维度。
a = np.array([[ 0, 0, 0], [10,10,10], [20,20,20], [30,30,30]]) #b数组与a数组形状不同 b = np.array([1,2,3]) print(a + b) # 其实就是b数组在纵向上向下拓展了3次(即将第一行重复3次) ''' [[ 1 2 3] [11 12 13] [21 22 23] [31 32 33]] '''
8. 数组的遍历
8.1 for循环遍历
当我们在NumPy中处理数组时,可以使用python的基本for循环来完成此操作。
arr = np.array([1, 2, 3]) for i in arr: print(i) ''' 1 2 3 '''
但当我们遍历多维数组时,需要嵌套多个for循环,十分不方便。
8.2 nditer迭代数组
NumPy提供了一个nditer迭代器对象,它可以配合for循环完成对数组元素的遍历。
a = np.arange(0,5) #使用nditer迭代器,并使用for进行遍历 for x in np.nditer(a): print(x) ''' 0 1 2 3 4 '''
也可以使用flat模块来迭代,见后文。
8.3 遍历中修改元素值
nditer对象提供了一个可选参数op_flags
,表示能否在遍历数组时对元素进行修改。
read-only
:只读。遍历时不可以修改read-write
:读写。遍历时可以修改write-only
:只写。遍历时可以修改
a = np.arange(0,60,5) a = a.reshape(3,4) print ("原数组是:",a) for x in np.nditer(a, op_flags=['readwrite']): x[...]=2*x print ('修改后的数组是:',a) ''' 原数组是: [[ 0 5 10 15] [20 25 30 35] [40 45 50 55]] 修改后的数组是: [[ 0 10 20 30] [ 40 50 60 70] [ 80 90 100 110]] '''
9. 数组函数
9.1 数学函数
NumPy设计了很多数学函数,这里列举其中最重要的几个。
- 绝对值函数:
np.abs(ndarray)
arr1 = np.arange(-1, -9, -1).reshape(2, 4) print(arr1) ''' [[-1 -2 -3 -4] [-5 -6 -7 -8]] ''' arr2 = np.abs(arr1) print(arr2) ''' [[1 2 3 4] [5 6 7 8]] '''
- 三角函数:
np.sin/tan/cos(ndarray)
arr1 = np.arange(3) * np.pi /2 print(arr1) ''' [0. 1.57079633 3.14159265] ''' sin_v = np.sin(arr1) cos_v = np.cos(arr1) tan_v = np.tan(arr1) print(sin_v) # [0.0000000e+00 1.0000000e+00 1.2246468e-16] print(cos_v) # [ 1.000000e+00 6.123234e-17 -1.000000e+00] print(tan_v) # [ 0.00000000e+00 1.63312394e+16 -1.22464680e-16]
- 指数函数:
np.exp(ndarray)
x = np.arange(1,4) print('x=', x) # x= [1 2 3] print('e^x=', np.exp(x)) # e^x= [ 2.71828183 7.3890561 20.08553692] print('2^x=', 2**x) # 2^x= [2 4 8] print('10^x=', 10**x) # 10^x= [ 10 100 1000]
- 对数函数:
np.log(ndarray)
x = np.array([1, 10, 100, 1000]) print('x=', x) # x= [ 1 10 100 1000] print('ln(x)=', np.log(x)) # ln(x)= [0. 2.30258509 4.60517019 6.90775528] print('log2(x)=', np.log(x)/np.log(2)) # log2(x)= [0. 3.32192809 6.64385619 9.96578428] print('log10(x)=', np.log(x)/np.log(10)) # log10(x)= [0. 1. 2. 3.]
9.2 聚合函数
向量的聚合函数没有axis参数,矩阵有。
- 最大值函数:
np.max()
- 最小值函数:
np.min()
x = np.random.random((2,3)) print(x) ''' [[0.81851887 0.71184876 0.89578074] [0.81572543 0.77135001 0.29211341]] ''' print('按维度一求最大值(列)', np.max(x, axis=0)) # 按维度一求最大值(列) [0.81851887 0.77135001 0.89578074] print('按维度二求最大值(行)', np.max(x, axis=1)) # 按维度二求最大值(行) [0.89578074 0.81572543] print('整体求最大值', np.max(x)) # 整体求最大值 0.8957807420711369
- 求和函数:
np.sum()
- 求积函数:
np.prod()
x = np.arange(10).reshape(2, 5) print(x) ''' [[0 1 2 3 4] [5 6 7 8 9]] ''' print('按维度一求和(列)', np.sum(x, axis=0)) # 按维度一求和(列) [ 5 7 9 11 13] print('按维度二求和(行)', np.sum(x, axis=1)) # 按维度二求和(行) [10 35] print('整体求和', np.sum(x)) # 整体求和 45
- 均值函数:
np.mean()
- 标准差函数:
np.std()
x = np.arange(10).reshape(2, 5) print(x) ''' [[0 1 2 3 4] [5 6 7 8 9]] ''' print('按维度一求平均(列)', np.mean(x, axis=0)) # 按维度一求平均(列) [2.5 3.5 4.5 5.5 6.5] print('按维度二求平均(行)', np.mean(x, axis=1)) # 按维度二求平均(行) [2. 7.] print('整体求平均', np.mean(x)) # 整体求平均 4.5
注意:
- 当
axis=0
时,最终结果与每一行的元素个数一致。 - 当
axis=1
时,最终结果与每一列的元素个数一致。
大型数组经常会出现缺失值,为了防止聚合函数报错,可以使用安全函数:所有聚合函数前面+nan。
如:np.nansum()、np.nanprod()
等
10. 布尔型数组
除了整数型数组和浮点型数组外,还有一种常见多用的数组叫布尔型数组。
10.1 创建布尔型数组
由于NumPy的主要数据类型是整数型数组和浮点型数组,因此布尔型数组的产生需要以下关系符:>、>=、==、!=、<、<=
arr = np.arange(1, 7).reshape(2, 3) print(arr) ''' [[1 2 3] [4 5 6]] ''' # 数组与数字作比较 print(arr > 4) ''' [[False False False] [False True True]] ''' arr1 = np.arange(1, 6) arr2 = np.flipud(arr1) print(arr1) # [1 2 3 4 5] print(arr2) # [5 4 3 2 1] # 同维度数组作比较 print(arr1 > arr2) ''' [False False False True True] '''
在Python中,逻辑运算符与、或、非是and、or、not
,而在NumPy中使用的是&、|、~
arr = np.arange(1, 10) print(arr) # [1 2 3 4 5 6 7 8 9] # 多个条件 print((arr < 4) | (arr > 6)) # [ True True True False False False True True True]
10.2 布尔型数组中与True数量有关的函数
np.sum()
:统计布尔型数组里True的个数
# 创建一个形状为10000的标准正态分布数组 data = np.random.randn(10000) print(data) ''' [-2.70125719 0.95444865 -1.84783368 ... -2.06167971 -1.49754748 -1.90110155] ''' # 统计该分布中绝对值小于1的元素个数 print(np.sum(np.abs(data) < 1)) # 6846(概率近似0.6827,符合统计学的3σ准则)
np.any()
:只要布尔型数组里含有一个及以上的True,即返回True
arr = np.arange(1, 10) arr2 = np.flipud(arr) print(arr) # [1 2 3 4 5 6 7 8 9] print(arr2) # [9 8 7 6 5 4 3 2 1] # 统计这两个数组里是否有共同元素 print(np.any(arr == arr2)) # True
np.all()
:当布尔型数组里全是True时,才返回True。
# 模拟英语六级成绩,创建10000个样本 arr = np.random.normal(500, 70, size=10000) print(arr) ''' [433.68180743 475.226045 529.23949592 ... 670.69732863 462.28717108 574.00076847] ''' # 判断是否所有考生都及格了(>425) print(np.all(arr > 425)) # False
10.3 掩码
掩码,即筛选条件。
若一个普通数组和一个布尔型数组的维度相同,可以将布尔型数组作为普通数组的掩码,以达到筛选普通数组元素的目的。
mask = np.array([0, 1, 1, 1, 0, 0, 1, 0, 0, 1], dtype=bool) print(mask) # [False True True True False False True False False True] arr = np.arange(0, 100, 10) print(arr) # [ 0 10 20 30 40 50 60 70 80 90] # 切片 print(arr[mask]) # [10 20 30 60 90] (只保留True对应位置的元素)
10.4 定位
语法:np.where()
where函数用于在很长的一个数组中定位满足某个条件的元素的索引位置。
# 模拟英语六级成绩,创建1000个样本 arr = np.random.normal(500, 70, size=1000) # 找出六级成绩超过 650 的元素所在位置 print(np.where(arr > 650)) ''' (array([ 48, 54, 202, 212, 290, 489, 570, 626, 687, 689, 735]),) ''' # 找出六级成绩最高分的元素所在位置 print(np.where(arr == np.max(arr))) # (array([687]),)
由实例可看出,np.where()
函数输出的是一个元组,第一个值是位置信息,第二个值是数据类型,若只想获得位置信息,可以使用np.where()[0]
。
print(np.where(arr == np.max(arr))[0]) # [687]
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 25岁的心里话
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 按钮权限的设计及实现