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]
标签:基本,10,arr,arr1,np,数组,使用,print,NumPy
From: https://www.cnblogs.com/-ula/p/18475241