目录
本文的Jupyter notebook脚本文件等请从百度网盘下载
第二章 Numpy库
2.0 引子
2.0.1 list VS. ndarray
numpy 的核心是 ndarray 对象(numpy 数组),它封装了 python 原生的同数据类型的 n 维数组(python 数组)。numpy 数组和 python 数组之间有几个重要的区别:
- numpy 数组一旦创建,其元素数量就不能再改变了。 增删 ndarray 元素的操作,意味着创建一个新数组并删除原来的数组。python 数组的元素则可以动态增减不同,
- numpy 数组中的元素都需要具有相同的数据类型,因此在内存中的大小相同。 python 数组则无此要求。
- numpy 数组的方法涵盖了大量数学运算和复杂操作,许多方法在最外层的 numpy 命名空间中都有对应的映射函数。和 python 数组相比,numpy 数组的方法功能更强大,执行效率更高,代码更简洁。
然而,以上的差异并没有真正体现出 ndarray 的优势之所在,ndarray 的精髓在于 numpy 的两大特征:矢量化(vectorization)和广播(broadcast)。矢量化可以理解为代码中没有显式的循环、索引等,广播可以理解为隐式地对每个元素实施操作。矢量化和广播理解起来有点抽象,我们还是举个栗子来说明一下吧。
例题: a 和 b 是等长的两个整数数组,求 a 和 b 对应元素之积组成的数组。
1.用 python 数组实现:
c = list()
for i in range(len(a)):
c.append(a[i]*b[i])
```
用 numpy 数组实现:
```python
c = a*b
list1 = [1,2,3]
id(list1)
2323276417416
list1.append(4)
print(list1)
id(list1)
[1, 2, 3, 4]
2323276417416
2.0.2 dtype AND shape
子曰:找对象先了解品行,学对象先了解属性。
ndarray 对象有很多属性,详见下表。
属性 | 说明 |
---|---|
ndarray.dtype | 元素类型 |
ndarray.shape | 数组的结构 |
ndarray.ndim | 秩,即轴的数量或维度的数量 |
ndarray.size | 数组元素的个数 |
ndarray.itemsize | 每个元素的大小,以字节为单位 |
ndarray.flags | 数组的内存信息 |
ndarray.real | 元素的实部 |
ndarray.imag | 元素的虚部 |
ndarray.data | 数组元素的实际存储区 |
基于以下三个原因,我认为,dtype 和 shape 是 ndarray 最重要的两个属性,重要到几乎可以忽略其他的属性。
- 我们趟过的坑,几乎都是 dtype 挖的
- 我们的迷茫,几乎都是因为 shape 和我们期望的不一样
- 我们的工作,很多都是在改变 shape
ndarray.astype() 可以修改元素类型 ,不能够直接对ndarray.dtype赋值进行更改
ndarray.reshape() 可以重新定义数组的结构,
这两个方法的重要性和其对应的属性一样。记住这两个属性和对应的两个方法,就算是登堂入室了。
import numpy as np
a = np.arange(5)
print(a)
a.dtype
[0 1 2 3 4]
dtype('int32')
a.dtype='float32'
print(a)
a.dtype
[0.e+00 1.e-45 3.e-45 4.e-45 6.e-45]
dtype('float32')
2.1 为什么要用Numpy
2.1.1 低效的Python for循环
【例】 求100万个数的倒数
import numpy as np
def compute_reciprocals(values):
res = []
for value in values: # 每遍历到一个元素,就要判断其类型,并查找适用于该数据类型的正确函数
res.append(1/value)
return res
values = list(range(1, 1000000))
%timeit compute_reciprocals(values)
145 ms ± 13.7 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)
%timeit :ipython中统计运行时间的魔术方法(多次运行取平均值)
values = np.arange(1, 1000000)
%timeit 1/values
2.64 ms ± 40.2 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
实现相同计算,Numpy的运行速度是Python循环的25倍,产生了质的飞跃
2.1.2 Numpy为什么如此高效
Numpy 是由C语言编写的
1、编译型语言VS解释型语言
C语言执行时,对代码进行整体编译,速度更快
2、连续单一类型存储VS分散多变类型存储
(1)Numpy数组内的数据类型必须是统一的,如全部是浮点型,而Python列表支持任意类型数据的填充
(2)Numpy数组内的数据连续存储在内存中,而Python列表的数据分散在内存中
这种存储结构,与一些更加高效的底层处理方式更加的契合
3、多线程VS线程锁
Python语言执行时有线程锁,无法实现真正的多线程并行,而C语言可以
2.1.3 什么时候用Numpy
在数据处理的过程中,遇到使用“Python for循环” 实现一些向量化、矩阵化操作的时候,要优先考虑用Numpy
如: 1、两个向量的点乘
2、矩阵乘法
2.2 Numpy数组的创建
2.2.1 从列表开始创建
import numpy as np
x = np.array([1, 2, 3, 4, 5])
print(x)
[1 2 3 4 5]
print(type(x))
print(x.shape)
<class 'numpy.ndarray'>
(5,)
- 设置数组的数据类型
x = np.array([1, 2, 3, 4, 5], dtype="float32")
print(x)
print(type(x))
print(type(x[0]))
[1. 2. 3. 4. 5.]
<class 'numpy.ndarray'>
<class 'numpy.float32'>
my_list = [1, 2, 3, 4, 5]
my_numpy_list = np.array(my_list)
my_numpy_list
array([1, 2, 3, 4, 5])
q = my_numpy_list.astype(float)
q.dtype
dtype('float64')
- 二维数组
x = np.array([[1, 2, 3],
[4, 5, 6],
[7, 8, 9]])
print(x)
print(x.shape)
[[1 2 3]
[4 5 6]
[7 8 9]]
(3, 3)
my_list0 = [[1,2,3,9],[5,4,0,3],[7,4,8,1]]
mn = np.array(my_list0) #创建二维数组
mn
array([[1, 2, 3, 9],
[5, 4, 0, 3],
[7, 4, 8, 1]])
?np.array
mn.tolist() #数组转化为列表
[[1, 2, 3, 9], [5, 4, 0, 3], [7, 4, 8, 1]]
2.2.2 从头创建数组(利用方法生成特殊数组)
- .zeros() : 全零
- .ones() : 全1
- .full() : 根据给定值填充
- .eye() :单位阵(斜线上为1)
- .arange() : 线性序列
- .linspace() : 线性等分
- .logspace() : 等比序列
- 生成随机数数组
- .random.random: 生成0~1之间数字构成的随机数数组
- .random.normal: 生成正态分布的随机数数组
- .random.randint:生成随机整数数组
- .random.permutation: 基于已有的序列,随机重排序
- .random.shuffle: 基于已有的序列,随机重排序
- .random.choice: 从序列中随机选取出来组成数组
- 依据已有数组的形状创建数组
- .ones_like:
- .zeros_like:
- .full_like:
(1)np.zeros()
?np.zeros
# 创建长度为5的数组,值都为0
np.zeros(5, dtype=int)
array([0, 0, 0, 0, 0])
zero = np.zeros((2,3)) #产生形状为(2,3)全0的数组
zero
array([[0., 0., 0.],
[0., 0., 0.]])
(2)np.ones
# 创建一个2*4的浮点型数组,值都为1
np.ones((2, 4), dtype=float)
array([[1., 1., 1., 1.],
[1., 1., 1., 1.]])
one = np.ones((6,3)) #产生形状为(6,3)全1的数组
one
array([[1., 1., 1.],
[1., 1., 1.],
[1., 1., 1.],
[1., 1., 1.],
[1., 1., 1.],
[1., 1., 1.]])
(3)np.full
np.full(5,9.9)
array([9.9, 9.9, 9.9, 9.9, 9.9])
# 创建一个3*5的数组,值都为8.8
np.full((3, 5), 8.8)
array([[8.8, 8.8, 8.8, 8.8, 8.8],
[8.8, 8.8, 8.8, 8.8, 8.8],
[8.8, 8.8, 8.8, 8.8, 8.8]])
(4)np.eye
?np.eye
# 创建一个3*3的单位矩阵
np.eye(3)
array([[1., 0., 0.],
[0., 1., 0.],
[0., 0., 1.]])
eye1 = np.eye(3,5)
eye1
array([[1., 0., 0., 0., 0.],
[0., 1., 0., 0., 0.],
[0., 0., 1., 0., 0.]])
(5)np.arange
?np.arange
# 创建一个线性序列数组,从1开始,到15结束,步长为2
np.arange(1, 15, 2)
array([ 1, 3, 5, 7, 9, 11, 13])
(6)np.linspace
#创建一个4个元素的数组,这四个数均匀的分配到0~1
np.linspace(0, 1, 4)
array([0. , 0.33333333, 0.66666667, 1. ])
(7)np.logspace
# 创建一个10个元素的数组,形成1~10^9的等比数列
np.logspace(0, 9, 10)
array([1.e+00, 1.e+01, 1.e+02, 1.e+03, 1.e+04, 1.e+05, 1.e+06, 1.e+07,
1.e+08, 1.e+09])
(8)np.random.random
# 创建一个3*3的,在0~1之间均匀分布的随机数构成的数组
np.random.random((3,3))
array([[0.24347952, 0.41715541, 0.41363866],
[0.44869706, 0.18128167, 0.18568051],
[0.05705023, 0.0689205 , 0.74837661]])
(9)np.random.normal
# 创建一个3*3的,均值为0,标准差为1的正态分布随机数构成的数组
np.random.normal(0, 1, (3,3))
array([[-0.38530465, 0.17474932, 0.31129291],
[ 1.61626424, -2.18883854, 0.54043825],
[-0.9141666 , -0.03804043, -0.6645122 ]])
(10)np.random.randint
# 创建一个3*3的,在[0,10)之间随机整数构成的数组
np.random.randint(0, 10, (3,3))
array([[9, 1, 9],
[0, 3, 9],
[8, 5, 4]])
(11)np.random.permutation
# 随机重排列
x = np.array([10, 20, 30, 40])
np.random.permutation(x) # 生产新列表
array([20, 40, 10, 30])
print(x)
np.random.shuffle(x) # 修改原列表
print(x)
[10 20 30 40]
[20 40 10 30]
(12)np.random.choice
- 按指定形状采样 随机采样
x = np.arange(10, 25, dtype = float)
x
array([10., 11., 12., 13., 14., 15., 16., 17., 18., 19., 20., 21., 22.,
23., 24.])
np.random.choice(x, size=(4, 3))
array([[19., 23., 22.],
[22., 21., 13.],
[15., 21., 17.],
[14., 23., 19.]])
import numpy as np
np.random.choice(10, 10)
array([0, 4, 3, 7, 0, 5, 2, 5, 1, 9])
x = np.arange(5).reshape(1, 5)
x
x.sum(axis=1, keepdims=True)
array([[10]])
- 按概率采样
np.random.choice(x, size=(4, 3), p=x/np.sum(x))
array([[15., 21., 20.],
[23., 17., 18.],
[23., 15., 17.],
[19., 24., 22.]])
2.2.3 Numpy中的常数
- 正无穷:Inf=inf=infty=Infinity=PINF
- 负无穷:NINF
- 正零: PZERO
- 负零: NZERO
- 非数值:nan=NaN=NAN
- 自然数:e
- π \pi π: pi
- 伽马:euler_gamma
- None: newaxis
print(np.inf)
print(np.NINF)
print(np.PZERO)
print(np.NZERO)
print(np.nan)
print(np.e)
print(np.pi)
print(np.euler_gamma)
print(np.newaxis)
inf
-inf
0.0
-0.0
nan
2.718281828459045
3.141592653589793
0.5772156649015329
None
2.3 Numpy多维数组轴的理解与操作控制
2.3.1 一维数组的轴(特例)
一维NumPy数组只有一个轴(即axis=0)
2.3.2 二维数组轴的理解
在二维NumPy数组中,轴是沿行和列的方向
- AXIS 0 轴是沿着行(rows)的方向
在NumPy数组中,axis 0 是第一轴。对于二维或多维数组,axis 0 是沿行(row)向下的轴。(一维数组是特例,不适用此处解释,后续讲解)
- AXIS 1 轴是沿着列(columns)的方向
在NumPy数组中,axis 1 是第2根轴。对于二维或多维数组,axis 1 是沿列(columns)横穿的轴。
2.3.3 三维与多维数组
-
结合图像的理解:
- 二维图像,灰度图
- 二维图像,灰度图
-
结合图像的理解:
- 三位图像,RGB彩色图
- 三位图像,RGB彩色图
2.3.4 axis控制运算的轴方向
在带有axis参数的二维数组上使用np.sum()等聚合函数时,它会将二维数组折叠为一维数组。它会折叠数据并减少维度。
axis参数控制将聚合哪个轴,换句话说,axis参数控制哪个轴将被折叠。
将NumPy和函数与axis参数一起使用时,指定的轴是折叠的轴。
示例,先创建一个简单的数组:
分别使用 axis= 0 和 axis= 1 的NumPy求和函数sum:
另一个高维Numpy进行堆叠的例子
import numpy as np
a = np.array([[1, 2, 3, 44], [22, 32, 42, 42], [23, 3, 3, 43]])
b = np.array([[2, 3, 4, 44], [42, 52, 62, 42], [23, 3, 3, 43]])
print(a)
print(b)
print("\n")
# 合并a b两个数组
print("===========np.stack((a, b), axis=0)==========")
print(np.stack((a, b), axis=0)) # 2,3,4
print("===========np.stack((a, b), axis=1)==========")
print(np.stack((a, b), axis=1))
print("===========np.stack((a, b), axis=2)==========")
print(np.stack((a, b), axis=2))
[[ 1 2 3 44]
[22 32 42 42]
[23 3 3 43]]
[[ 2 3 4 44]
[42 52 62 42]
[23 3 3 43]]
===========np.stack((a, b), axis=0)==========
[[[ 1 2 3 44]
[22 32 42 42]
[23 3 3 43]]
[[ 2 3 4 44]
[42 52 62 42]
[23 3 3 43]]]
===========np.stack((a, b), axis=1)==========
[[[ 1 2 3 44]
[ 2 3 4 44]]
[[22 32 42 42]
[42 52 62 42]]
[[23 3 3 43]
[23 3 3 43]]]
===========np.stack((a, b), axis=2)==========
[[[ 1 2]
[ 2 3]
[ 3 4]
[44 44]]
[[22 42]
[32 52]
[42 62]
[42 42]]
[[23 23]
[ 3 3]
[ 3 3]
[43 43]]]
2.4 Numpy数组的性质
2.4.1 数组的属性
- shape: 形状
- ndim:维度
- size:数组中元素的个数
- itemsize:数组中每个元素的空间大小,以字节为单位
- dtype:返回数组元素的数据类型
- nbytes:所有元素所占空间的大小,以字节为单位
x = np.random.randint(10, size=(3, 4))
x
array([[8, 6, 6, 1],
[3, 1, 1, 8],
[2, 9, 8, 3]])
1、数组的形状shape
x.shape
(3, 4)
2、数组的维度ndim
x.ndim
2
y = np.arange(10)
y
array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])
y.ndim
1
3、数组的大小size
x.size
12
4、每个元素所占空间的大小itemsize
x.itemsize
4
5、数组的数据类型dtype
x.dtype
dtype('int32')
6、数组所有元素所占空间的大小nbytes
x.nbytes
48
2.4.2 数组索引
1、一维数组的索引
x1 = np.arange(10)
x1
array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])
x1[0]
0
x1[5]
5
x1[-1]
9
2、多维数组的索引——以二维为例
x2 = np.random.randint(0, 20, (2,3))
x2
array([[ 7, 8, 18],
[ 5, 13, 13]])
x2[0, 2]
18
x2[0][2]
18
注意:numpy数组的数据类型是固定的,向一个整型数组插入一个浮点值,浮点值会向下进行取整
x2[0, 0] = 1.618
x2
array([[ 1, 8, 18],
[ 5, 13, 13]])
2.4.3 数组的切片
1、一维数组——跟列表一样
x1 = np.arange(10)
x1
array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])
x1[:3]
array([0, 1, 2])
x1[3:]
array([3, 4, 5, 6, 7, 8, 9])
x1[::-1]
array([9, 8, 7, 6, 5, 4, 3, 2, 1, 0])
2、多维数组——以二维为例
x2 = np.random.randint(20, size=(3,4))
x2
array([[12, 12, 8, 18],
[12, 1, 16, 4],
[14, 13, 5, 1]])
x2[1,1]
1
x2[:2, :3] # 前两行,前三列
array([[12, 12, 8],
[12, 1, 16]])
x2[1] # 把二维看作一个列表,第2个元素
array([12, 1, 16, 4])
x2[:2, 0:3:2] # 前两行 前三列(每隔一列)
array([[14, 15],
[18, 16]])
x2[::-1, ::-1]
array([[17, 2, 8, 0],
[17, 16, 8, 18],
[ 8, 15, 9, 14]])
x3 = np.random.randint(60, size=(3,4,5))
x3
array([[[33, 13, 57, 41, 29],
[ 0, 14, 26, 36, 26],
[48, 5, 30, 59, 55],
[28, 23, 14, 16, 43]],
[[17, 55, 21, 37, 9],
[22, 7, 25, 39, 33],
[57, 48, 0, 46, 37],
[17, 47, 2, 33, 42]],
[[13, 31, 45, 2, 18],
[16, 10, 28, 27, 1],
[32, 46, 54, 44, 10],
[ 9, 20, 20, 2, 54]]])
x3[0]
array([[33, 13, 57, 41, 29],
[ 0, 14, 26, 36, 26],
[48, 5, 30, 59, 55],
[28, 23, 14, 16, 43]])
x3[0,0]
array([33, 13, 57, 41, 29])
x3[0,0,0]
33
3、获取数组的行和列
x3 = np.random.randint(20, size=(3,4))
x3
array([[ 8, 13, 15, 7],
[19, 13, 17, 6],
[11, 2, 0, 12]])
x3[1, :] #第一行 从0开始计数
array([19, 13, 17, 6])
x3[1] # 第一行简写
array([19, 13, 17, 6])
x3[:, 2] # 第二列 从0开始计数
array([15, 17, 0])
4、切片获取的是视图,而非副本
x4 = np.random.randint(20, size=(3,4))
x4
array([[ 5, 14, 7, 2],
[ 8, 12, 9, 3],
[19, 0, 10, 7]])
x5 = x4[:2, :2]
x5
array([[ 5, 14],
[ 8, 12]])
注意:视图元素发生修改,则原数组亦发生相应修改
x5[0, 0] = 0
x5
array([[ 0, 14],
[ 8, 12]])
x4
array([[ 0, 14, 7, 2],
[ 8, 12, 9, 3],
[19, 0, 10, 7]])
修改切片的安全方式:copy
x4 = np.random.randint(20, size=(3,4))
x4
array([[18, 14, 10, 12],
[10, 16, 7, 19],
[ 3, 16, 3, 12]])
x6 = x4[:2, :2].copy()
x6
array([[18, 14],
[10, 16]])
x6[0, 0] = 0
x6
array([[ 0, 14],
[10, 16]])
x4
array([[18, 14, 10, 12],
[10, 16, 7, 19],
[ 3, 16, 3, 12]])
2.4.4 数组的变形
x5 = np.random.randint(0, 10, (12,))
x5
array([7, 5, 1, 5, 2, 3, 0, 1, 8, 5, 9, 1])
x5.shape
(12,)
x6 = x5.reshape(3, 4)
x6
array([[7, 5, 1, 5],
[2, 3, 0, 1],
[8, 5, 9, 1]])
注意:reshape返回的是视图,而非副本
x6[0, 0] = 0
x5
array([0, 5, 1, 5, 2, 3, 0, 1, 8, 5, 9, 1])
一维向量转行向量
x5.ndim
1
x7 = x5.reshape(1, x5.shape[0])
x7
array([[0, 5, 1, 5, 2, 3, 0, 1, 8, 5, 9, 1]])
x7.ndim
2
x8 = x5[np.newaxis, :]
x8
array([[0, 5, 1, 5, 2, 3, 0, 1, 8, 5, 9, 1]])
一维向量转列向量
x7 = x5.reshape(x5.shape[0], 1)
x7
array([[0],
[5],
[1],
[5],
[2],
[3],
[0],
[1],
[8],
[5],
[9],
[1]])
x8 = x5[:, np.newaxis]
x8
array([[0],
[5],
[1],
[5],
[2],
[3],
[0],
[1],
[8],
[5],
[9],
[1]])
多维向量转一维向量
x6 = np.random.randint(0, 10, (3, 4))
x6
array([[3, 7, 6, 4],
[4, 5, 6, 3],
[7, 6, 2, 3]])
flatten返回的是副本
x9 = x6.flatten()
x9
array([3, 7, 6, 4, 4, 5, 6, 3, 7, 6, 2, 3])
x9[0]=0
x6
array([[3, 7, 6, 4],
[4, 5, 6, 3],
[7, 6, 2, 3]])
ravel返回的是视图
x10 = x6.ravel()
x10
array([3, 7, 6, 4, 4, 5, 6, 3, 7, 6, 2, 3])
x10[0]=0
x6
array([[0, 7, 6, 4],
[4, 5, 6, 3],
[7, 6, 2, 3]])
reshape返回的是视图
x11 = x6.reshape(-1)
x11
array([0, 7, 6, 4, 4, 5, 6, 3, 7, 6, 2, 3])
x11[0]=10
x6
array([[10, 7, 6, 4],
[ 4, 5, 6, 3],
[ 7, 6, 2, 3]])
2.4.5 数组的拼接
x1 = np.array([[1, 2, 3],
[4, 5, 6]])
x2 = np.array([[7, 8, 9],
[0, 1, 2]])
1、水平拼接——非视图
x3 = np.hstack([x1, x2])
x3
array([[1, 2, 3, 7, 8, 9],
[4, 5, 6, 0, 1, 2]])
x3[0][0] = 0
x1
array([[1, 2, 3],
[4, 5, 6]])
x4 = np.c_[x1, x2]
x4
array([[1, 2, 3, 7, 8, 9],
[4, 5, 6, 0, 1, 2]])
x4[0][0] = 0
x1
array([[1, 2, 3],
[4, 5, 6]])
2、垂直拼接——非视图
x1 = np.array([[1, 2, 3],
[4, 5, 6]])
x2 = np.array([[7, 8, 9],
[0, 1, 2]])
x5 = np.vstack([x1, x2])
x5
array([[1, 2, 3],
[4, 5, 6],
[7, 8, 9],
[0, 1, 2]])
x6 = np.r_[x1, x2]
x6
array([[1, 2, 3],
[4, 5, 6],
[7, 8, 9],
[0, 1, 2]])
2.4.6 数组的分裂
1、split的用法
x6 = np.arange(10)
x6
array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])
x1, x2, x3 = np.split(x6, [2, 7])
print(x1, x2, x3)
[0 1] [2 3 4 5 6] [7 8 9]
2、hsplit的用法
x7 = np.arange(1, 26).reshape(5, 5)
x7
array([[ 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]])
left, middle, right = np.hsplit(x7, [2,4])
print("left:\n", left) # 第0~1列
print("middle:\n", middle) # 第2~3列
print("right:\n", right) # 第4列
left:
[[ 1 2]
[ 6 7]
[11 12]
[16 17]
[21 22]]
middle:
[[ 3 4]
[ 8 9]
[13 14]
[18 19]
[23 24]]
right:
[[ 5]
[10]
[15]
[20]
[25]]
3、vsplit的用法
x7 = np.arange(1, 26).reshape(5, 5)
x7
array([[ 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]])
upper, middle, lower = np.vsplit(x7, [2,4])
print("upper:\n", upper) # 第0~1行
print("middle:\n", middle) # 第2~3行
print("lower:\n", lower) # 第4行
upper:
[[ 1 2 3 4 5]
[ 6 7 8 9 10]]
middle:
[[11 12 13 14 15]
[16 17 18 19 20]]
lower:
[[21 22 23 24 25]]
2.5 Numpy四大运算
2.5.1 向量化运算
1、与数字的加减乘除等
x1 = np.arange(1,6)
x1
array([1, 2, 3, 4, 5])
print("x1+5", x1+5)
print("x1-5", x1-5)
print("x1*5", x1*5)
print("x1/5", x1/5)
x1+5 [ 6 7 8 9 10]
x1-5 [-4 -3 -2 -1 0]
x1*5 [ 5 10 15 20 25]
x1/5 [0.2 0.4 0.6 0.8 1. ]
print("-x1", -x1)
print("x1**2", x1**2)
print("x1//2", x1//2)
print("x1%2", x1%2)
-x1 [-1 -2 -3 -4 -5]
x1**2 [ 1 4 9 16 25]
x1//2 [0 1 1 2 2]
x1%2 [1 0 1 0 1]
# 注意区别于list的加减
list1 = [1,2,3,4,5]
list1+[6]
[1, 2, 3, 4, 5, 6]
2、绝对值、三角函数、指数、对数
(1)绝对值
x2 = np.array([1, -1, 2, -2, 0])
x2
array([ 1, -1, 2, -2, 0])
abs(x2)
array([1, 1, 2, 2, 0])
np.abs(x2)
array([1, 1, 2, 2, 0])
(2)三角函数
theta = np.linspace(0, np.pi, 3)
theta
array([0. , 1.57079633, 3.14159265])
print("sin(theta)", np.sin(theta))
print("con(theta)", np.cos(theta))
print("tan(theta)", np.tan(theta))
sin(theta) [0.0000000e+00 1.0000000e+00 1.2246468e-16]
con(theta) [ 1.000000e+00 6.123234e-17 -1.000000e+00]
tan(theta) [ 0.00000000e+00 1.63312394e+16 -1.22464680e-16]
x = [1, 0 ,-1]
print("arcsin(x)", np.arcsin(x))
print("arccon(x)", np.arccos(x))
print("arctan(x)", np.arctan(x))
arcsin(x) [ 1.57079633 0. -1.57079633]
arccon(x) [0. 1.57079633 3.14159265]
arctan(x) [ 0.78539816 0. -0.78539816]
(3)指数运算
x = np.arange(3)
x
array([0, 1, 2])
np.exp(x)
array([1. , 2.71828183, 7.3890561 ])
(4)对数运算
x = np.array([1, 2, 4, 8 ,10])
print("ln(x)", np.log(x))
print("log2(x)", np.log2(x))
print("log10(x)", np.log10(x))
ln(x) [0. 0.69314718 1.38629436 2.07944154 2.30258509]
log2(x) [0. 1. 2. 3. 3.32192809]
log10(x) [0. 0.30103 0.60205999 0.90308999 1. ]
3、两个数组的运算
x1 = np.arange(1,6)
x1
array([1, 2, 3, 4, 5])
x2 = np.arange(6,11)
x2
array([ 6, 7, 8, 9, 10])
print("x1+x2:", x1+x2)
print("x1-x2:", x1-x2)
print("x1*x2:", x1*x2)
print("x1/x2:", x1/x2)
x1+x2: [ 7 9 11 13 15]
x1-x2: [-5 -5 -5 -5 -5]
x1*x2: [ 6 14 24 36 50]
x1/x2: [0.16666667 0.28571429 0.375 0.44444444 0.5 ]
注意区别于list运算
list1 = list(range(1,6))
print(list1)
list2 = list(range(6,11))
print(list2)
list1+list2
[1, 2, 3, 4, 5]
[6, 7, 8, 9, 10]
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
2.5.2 矩阵运算
x = np.arange(9).reshape(3, 3)
x
array([[0, 1, 2],
[3, 4, 5],
[6, 7, 8]])
- 矩阵的转置
y = x.T
y
array([[0, 3, 6],
[1, 4, 7],
[2, 5, 8]])
- 矩阵乘法
x = np.array([[1, 0],
[1, 1]])
y = np.array([[0, 1],
[1, 1]])
x.dot(y)
array([[0, 1],
[1, 2]])
np.dot(x, y)
array([[0, 1],
[1, 2]])
y.dot(x)
array([[1, 1],
[2, 1]])
np.dot(y, x)
array([[1, 1],
[2, 1]])
注意跟x*y的区别
- 元素对应相乘
x*y
array([[0, 0],
[1, 1]])
2.5.3 广播运算
举个栗子
a = 2
print("a\n", a,"\n")
b = np.array([1,2])
print("b\n",b,"\n")
c = np.arange(1,7).reshape(3,2)
print("c\n",c,"\n")
d = np.arange(1,9).reshape(2,2,2)
print("d\n",d,"\n")
e = np.arange(1,5).reshape(2,2)
print("e\n",e,"\n")
a
2
b
[1 2]
c
[[1 2]
[3 4]
[5 6]]
d
[[[1 2]
[3 4]]
[[5 6]
[7 8]]]
e
[[1 2]
[3 4]]
- ① 标量和一维、二维、三维数组之间的广播运算
print("a\n",a,"\n")
print("b\n",b,"\n")
print("a+b\n",a+b,"\n")
a
2
b
[1 2]
a+b
[3 4]
print("a\n",a,"\n")
print("c\n",c,"\n")
print("a+c\n",a+c,"\n")
a
2
c
[[1 2]
[3 4]
[5 6]]
a+c
[[3 4]
[5 6]
[7 8]]
print("a\n",a,"\n")
print("d\n",d,"\n")
print("a+d\n",a+d,"\n")
a
2
d
[[[1 2]
[3 4]]
[[5 6]
[7 8]]]
a+d
[[[ 3 4]
[ 5 6]]
[[ 7 8]
[ 9 10]]]
- ② 一维数组和二维、三维数组之间的广播运算
print("b\n",b,"\n")
print("c\n",c,"\n")
print("b+c\n",b+c,"\n")
b
[1 2]
c
[[1 2]
[3 4]
[5 6]]
b+c
[[2 4]
[4 6]
[6 8]]
print("b\n",b,"\n")
print("d\n",d,"\n")
print("b+d\n",b+d,"\n")
b
[1 2]
d
[[[1 2]
[3 4]]
[[5 6]
[7 8]]]
b+d
[[[ 2 4]
[ 4 6]]
[[ 6 8]
[ 8 10]]]
- ③ 二维数组和三维数组元素之间的广播运算
print("e\n",e,"\n")
print("d\n",d,"\n")
print("e+d\n",e+d,"\n")
e
[[1 2]
[3 4]]
d
[[[1 2]
[3 4]]
[[5 6]
[7 8]]]
e+d
[[[ 2 4]
[ 6 8]]
[[ 6 8]
[10 12]]]
print("c\n",c,"\n")
print("d\n",d,"\n")
print("c+d\n",c+d,"\n")
c
[[1 2]
[3 4]
[5 6]]
d
[[[1 2]
[3 4]]
[[5 6]
[7 8]]]
---------------------------------------------------------------------------
ValueError Traceback (most recent call last)
<ipython-input-27-e2835d3806eb> in <module>
1 print("c\n",c,"\n")
2 print("d\n",d,"\n")
----> 3 print("c+d\n",c+d,"\n")
ValueError: operands could not be broadcast together with shapes (3,2) (2,2,2)
可以看出:不同形状数组之间,有时候可以触发广播机制,有时候却又不能。那么,触发广播机制,需要什么条件呢?
触发“广播机制”的条件
观察下面的表:
记住下面两句话:
- 对于一个标量,可以将这一个数字的形状看成是一行一列;
- 对于一个一维数组,可以将它的形状看成是一行多列;
对上述表和上面两句话,了解后,仔细观察下图:
不同形状的数组之间能不能触发广播机制,主要看对应形状的每一个位置上的数字,是否满足如下要求:
- ① 要么对应位置上的数字完全一致,可以触发广播机制,比如说第Ⅵ组;
- ② 对应位置上的数字要是不一样,那么对应位置上,必须有一个数字是1,比如说Ⅰ Ⅱ Ⅲ Ⅳ Ⅴ;
- ③ 如果对应位置上的数字不仅不相同,且没有任何一个的数字为1,那么就不能使用广播机制,比如说Ⅶ。
2.5.4 比较运算和掩码
- all:所有元素满足条件
- any:至少有一个满足条件
- unique:元素唯一化
1、比较运算
x1 = np.random.randint(100, size=(10,10))
x1
array([[57, 50, 47, 45, 38, 31, 39, 82, 72, 57],
[71, 38, 2, 69, 54, 61, 74, 77, 65, 39],
[78, 74, 0, 44, 79, 32, 84, 79, 53, 8],
[31, 94, 14, 43, 11, 32, 55, 35, 12, 3],
[95, 89, 9, 14, 99, 64, 30, 17, 74, 9],
[ 2, 42, 62, 36, 76, 39, 8, 46, 39, 87],
[26, 77, 79, 45, 6, 90, 33, 7, 15, 34],
[54, 80, 60, 24, 58, 29, 53, 14, 64, 58],
[48, 22, 3, 71, 24, 23, 74, 13, 73, 22],
[79, 7, 65, 66, 60, 34, 3, 66, 10, 55]])
x1 > 50
array([[ True, False, False, False, False, False, False, True, True,
True],
[ True, False, False, True, True, True, True, True, True,
False],
[ True, True, False, False, True, False, True, True, True,
False],
[False, True, False, False, False, False, True, False, False,
False],
[ True, True, False, False, True, True, False, False, True,
False],
[False, False, True, False, True, False, False, False, False,
True],
[False, True, True, False, False, True, False, False, False,
False],
[ True, True, True, False, True, False, True, False, True,
True],
[False, False, False, True, False, False, True, False, True,
False],
[ True, False, True, True, True, False, False, True, False,
True]])
2、操作布尔数组
import numpy as np
x2 = np.random.randint(10, size=(3, 4))
x2
array([[6, 8, 1, 9],
[7, 7, 1, 0],
[9, 4, 6, 6]])
print(x2 > 5)
np.sum(x2 > 5)
[[ True True False True]
[ True True False False]
[ True False True True]]
8
np.all(x2 > 5)
False
x2>1
array([[ True, True, False, True],
[ True, True, False, False],
[ True, True, True, True]])
np.all(x2>1, axis=1)
array([False, False, True])
np.any(x2 == 9)
True
x2
array([[4, 3, 8, 8],
[8, 9, 5, 1],
[8, 5, 2, 4]])
(x2 < 9) & (x2 >5)
array([[False, False, True, True],
[ True, False, False, False],
[ True, False, False, False]])
np.sum((x2 < 9) & (x2 >5))
4
np.sum(x2[(x2<9)&(x2>5)])
32
3、将布尔数组作为掩码
x2
array([[1, 4, 2, 9],
[8, 8, 2, 4],
[9, 5, 3, 6]])
x2 > 5
array([[False, False, False, True],
[ True, True, False, False],
[ True, False, False, True]])
x2[x2 > 5]
array([9, 8, 8, 9, 6])
4、元素唯一化
import numpy as np
arr = np.array([12, 11, 34, 23, 12, 8, 11])
# 查找数组的唯一元素
print(np.unique(arr))
[ 8 11 12 23 34]
2.5.5 花式索引与布尔索引
2.5.5.1 花式索引
1、一维数组
x = np.random.randint(100, size=10)
x
array([43, 69, 67, 9, 11, 27, 55, 93, 23, 82])
注意:结果的形状与索引数组ind一致
ind = [2, 6, 9]
x[ind]
array([67, 55, 82])
ind = np.array([[1, 0],
[2, 3]])
x[ind]
array([[69, 43],
[67, 9]])
2、多维数组
x = np.arange(12).reshape(3, 4)
x
array([[ 0, 1, 2, 3],
[ 4, 5, 6, 7],
[ 8, 9, 10, 11]])
row = np.array([0, 1, 2])
col = np.array([1, 3, 0])
x[row, col] # x(0, 1) x(1, 3) x(2, 0)
array([1, 7, 8])
row[:, np.newaxis] # 列向量
array([[0],
[1],
[2]])
x[row[:, np.newaxis], col] # 广播机制
array([[ 1, 3, 0],
[ 5, 7, 4],
[ 9, 11, 8]])
2.5.5.2 布尔索引
array_2d = np.arange(1, 10).reshape((3, 3))
print(array_2d)
print("------------")
# 使用布尔索引访问数组
print(array_2d > 5)
print("------------")
print(array_2d[array_2d > 5])
[[1 2 3]
[4 5 6]
[7 8 9]]
------------
[[False False False]
[False False True]
[ True True True]]
------------
[6 7 8 9]
array_2d = np.arange(1, 10).reshape((3, 3))
print(array_2d)
print("------------")
# 使用布尔索引访问数组
print(array_2d % 2 == 1)
print("------------")
print(array_2d[array_2d % 2 == 1])
[[1 2 3]
[4 5 6]
[7 8 9]]
------------
[[ True False True]
[False True False]
[ True False True]]
------------
[1 3 5 7 9]
2.6 其他Numpy通用函数
2.6.1 数值排序
x = np.random.randint(20, 50, size=10)
x
array([48, 27, 44, 24, 34, 21, 24, 30, 34, 46])
- 产生新的排序数组
np.sort(x)
array([21, 24, 24, 27, 30, 34, 34, 44, 46, 48])
x
array([48, 27, 44, 24, 34, 21, 24, 30, 34, 46])
- 替换原数组
x.sort()
x
array([21, 24, 24, 27, 30, 34, 34, 44, 46, 48])
- 获得排序索引
x = np.random.randint(20, 50, size=10)
x
array([27, 36, 35, 28, 34, 20, 21, 49, 48, 30])
i = np.argsort(x)
i
array([5, 6, 0, 3, 9, 4, 2, 1, 8, 7], dtype=int64)
2.6.2 最大最小值
x = np.random.randint(20, 50, size=10)
x
array([48, 31, 30, 44, 48, 33, 44, 48, 39, 35])
print("max:", np.max(x))
print("min:", np.min(x))
max: 48
min: 30
print("max_index:", np.argmax(x))
print("min_index:", np.argmin(x))
max_index: 0
min_index: 2
2.6.3 数值求和、求积
x = np.arange(1,6)
x
array([1, 2, 3, 4, 5])
x.sum()
15
np.sum(x)
15
x1 = np.arange(6).reshape(2,3)
x1
array([[0, 1, 2],
[3, 4, 5]])
- 按行求和
np.sum(x1, axis=1)
array([ 3, 12])
- 按列求和
np.sum(x1, axis=0)
array([3, 5, 7])
- 全体求和
np.sum(x1)
15
- 求积
x
array([1, 2, 3, 4, 5])
x.prod()
120
np.prod(x)
120
2.6.4 中位数、均值、方差、标准差
x = np.random.normal(0, 1, size=10000)
import matplotlib.pyplot as plt
plt.hist(x, bins=50)
plt.show()
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-xXctxT82-1647677176517)(output_327_0.png)]
- 中位数
np.median(x)
-0.01024418366119727
- 均值
x.mean()
-0.004164442327293362
np.mean(x)
-0.004164442327293362
- 方差
x.var()
1.0221853234535774
np.var(x)
1.0221853234535774
- 标准差
x.std()
1.0110318112965473
np.std(x)
1.0110318112965473
import numpy as np
x1 = np.array([[1,2,3,4],
[2,3,4,5]])
x2 = [3,4,5,6]
print(x1+x2)
[[ 4 6 8 10]
[ 5 7 9 11]]
{2,3,5,8}-{1,2,3,4,6}
{5, 8}
2.6.5 数组转置函数
- T属性:
- swapaxes():
- transpose():
1、T属性
import numpy as np
arr = np.arange(10).reshape(2,5)
print(f"arr形状:{arr.shape}")
print(arr)
arr形状:(2, 5)
[[0 1 2 3 4]
[5 6 7 8 9]]
# 使用T属性进行转置
new_arr = arr.T
print(f"new_arr形状:{new_arr.shape}")
print(new_arr)
new_arr形状:(5, 2)
[[0 5]
[1 6]
[2 7]
[3 8]
[4 9]]
2、swapaxes()
import numpy as np
arr = np.arange(24).reshape(2, 3, 4)
print(f"arr形状:{arr.shape}")
print(arr)
arr形状:(2, 3, 4)
[[[ 0 1 2 3]
[ 4 5 6 7]
[ 8 9 10 11]]
[[12 13 14 15]
[16 17 18 19]
[20 21 22 23]]]
# 使用swapaxes()方法进行数组转置,互换1号轴和2号轴的元素
new_arr = arr.swapaxes(2, 1)
print(f"new_arr形状:{new_arr.shape}")
print(new_arr)
new_arr形状:(2, 4, 3)
[[[ 0 4 8]
[ 1 5 9]
[ 2 6 10]
[ 3 7 11]]
[[12 16 20]
[13 17 21]
[14 18 22]
[15 19 23]]]
3、transpose()
import numpy as np
arr = np.arange(24).reshape(2,3,4)
print(f"arr形状:{arr.shape}")
print(arr)
arr形状:(2, 3, 4)
[[[ 0 1 2 3]
[ 4 5 6 7]
[ 8 9 10 11]]
[[12 13 14 15]
[16 17 18 19]
[20 21 22 23]]]
# 使用transpose()方法进行转置
new_arr = arr.transpose((1,2,0))
print(f"new_arr形状:{new_arr.shape}")
print(new_arr)
new_arr形状:(3, 4, 2)
[[[ 0 12]
[ 1 13]
[ 2 14]
[ 3 15]]
[[ 4 16]
[ 5 17]
[ 6 18]
[ 7 19]]
[[ 8 20]
[ 9 21]
[10 22]
[11 23]]]