共计3927个字符,预计需要花费10分钟才能阅读完成。
Python 库 Numpy 入门
NumPy 是 Python 中科学计算的基本包。它是一个 Python 库,提供多维数组对象、各种派生对象(如掩码数组和矩阵),以及用于对数组进行快速操作的各种例程,包括数学、逻辑、形状操作、排序、选择、I/O、离散傅立叶变换、基本线性代数、基本统计运算、随机模拟等等。
numpy 的核心是 ndarray 对象,这是一个多维数组。
安装
用 pip 安装
pip install numpy
官网下载
基本使用
多维数组概念
在 numpy 中,维度 (dimensions) 被称作 轴(axes)。
[[0 1 2 3 4]
[5 6 7 8 9]
[10 11 12 13 14]]
在上面这个数组中,有两个轴,即是二维数组(二维空间)。第一个轴有三个元素,即分别为 [0 1 2 3 4]
、[5 6 7 8 9]
和[10 11 12 13 14]
,长度为 3。第二个轴有五个元素,即长度为 5。
创建一个数组
numpy 数组的类为 ndarray,这有别于 python 标准库中的 array.array。
以下为创建 numpy 数组的示例:
# 先导入 numpy,别称为 np
import numpy as np
# 生成一个 5x3 的二维数组 a
a = np.arange(15).reshape(5,3)
print(a)
# 将会输出:# [[0 1 2]
# [3 4 5]
# [6 7 8]
# [9 10 11]
# [12 13 14]]
除此之外,ndarray 还有多种属性,如下:
# 数组的维数
print(a.ndim)
# 结果:2
# 表示数组为 2 维空间
# 数组的形状
print(a.shape)
# 结果:(5,3)
# 表示数组为 5x3 的二维数组
# 数组的类型(data type)
print(a.dtype)
# 数组中每个元素的大小(bit)
print(a.itemsize)
# 输出数组在内存中的真实数据
# 通常不会用到该属性
print(a.data)
同样,也能通过 python 标准库中的列表来创建 numpy 数组:
# 调用 np.array()方法即可把列表转换成数组
a = np.array([1,2,3])
# 同样浮点型也适用
a = np.array([1.2,2.4,1.8])
# 还可以转换成多维数组
b = np.array([(1.5, 2, 3), (4, 5, 6)])
print(b)
# 结果:# [[1.5 2. 3.]
# [4. 5. 6.]]
b = np.array([[1, 2], [1, 2]], dtype=complex)
# complex 是复数类型
为了提高效率,numpy 还提供了创建空数组的方法:
# 创建全为 0 的 2x3 的二维数组
np.zeros((2,3))
# 创建全为 1 的 2x3x4 的三维数组
np.ones((2,3,4))
# 创建空数组(数据值取决于内存, 即随机)
np.empty((2,3))
我们再回顾本段落第一个示例,里面用的 arange 方法可以生成一个递增或者递减的序列:
# np.arange(start,stop,step)
# 起始 结束 步进
# 创建一个从 [0,5) 的一个一维数组
a = np.arange(5)
print(a)
# 结果:[0 1 2 3 4]
# 创建一个从[10,30),步进为 5 的一维数组
a = np.arange(10,30,5)
# 结果:[10 15 20 25]
# 也可以是递减的
a = np.arange(30,10,-5)
# 结果:[30 25 20 15]
如果想生成带小数的序列,推荐使用 linspace 方法,它可以生成一个等间隔的序列:
# np.linspace(start,stop,num)
# 起始 结束 数的个数
# 把 [0,5] 等间距的分成 6 个数
d = np.linspace(0, 5, 6)
print(d)
# 结果:[0. 1. 2. 3. 4. 5.]
# 注意:间距 =(stop-start)/(num-1)
# 计算 sin(x)在 [0,2π] 区间内等间距的 10 个点的数值
from numpy import pi
x = np.linspace(0, 2 * np.pi, 10)
f = np.sin(x)
print(f)
# 结果:[ 0.00000000e+00 6.42787610e-01 9.84807753e-01 8.66025404e-01
# 3.42020143e-01 -3.42020143e-01 -8.66025404e-01 -9.84807753e-01
# -6.42787610e-01 -2.44929360e-16]
这些序列还可以用 reshape()
方法重新分配为新的多维数组:
# 创建一个 1~10 的 5x2 的二维数组
a = np.arange(1,11).reshape(5,2)
数组操作(基本运算)
先生成两个 ndarray 的变量:
a = np.array([10, 10, 10])
# [10,10,10]
b = np.arange(3)
# [0 ,1 ,2]
进行如下运算:
# a 数组减去 b 数组
a - b
# 得到:[10,9,8]
# b 数组的 2 次幂
b**2
# 得到:[0,1,4]
# b 数组是否小于 1
b < 1
# 得到:[True, False, False]
以下是多维数组的运算:
A = np.array([[1,1],
[0,1]])
B = np.array([[2,0],
[3,4]])
# 矩阵对应元素相乘
A * B
# 得到:# [[2 0]
# [0 4]]
# 以下运算才是矩阵的相乘(线性代数)
A @ B
# 得到:# [[5 4]
# [3 4]]
A.dot(B)
# 以上也能实现矩阵相乘 等同于 A@B
# 一个数乘以矩阵
3 * B
# 得到:# [[6 0]
# [9 12]]
A *= 3
# 相当于 A = A * 3
B += A
# 相当于 B = B + A
其他常见的运算:
# 复数运算
np.exp(B * 2j)
# j 代表复数
# 求和(数组内所有元素的和)
np.sum(B)
# 求最小元素
np.min(B)
# 求最大元素
np.max(B)
索引和切片
一维数组
对于一维数组而言,和 Python 自带的列表操作十分的相似:
# 产生 10 个元素的数组
a = np.arange(10)
# [0 1 2 3 4 5 6 7 8 9]
# 索引为 3 的元素表示为
a[3] # 3
# 注意索引从 0~9 共十个数
# 还可以进行切片 输出索引 2,3 的数
a[2:4] # [2 3]
# 也可以设置步长
# 如下可以实现逆序该数组
a[::-1] # [9 8 7 6 5 4 3 2 1 0]
# 遍历每一个元素
for t in a:
print(t)
多维数组
在多维数组中,对于每一个轴都有一个索引。
以下是二维数组操作的示例:
# [[0 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 28 29]]
a = np.arange(30).reshape(5,6)
# 取第 3 行第 4 个元素
# 索引依次为 2,3
a[2,3] # 15
# 当然也能进行切片
# 第一个索引表明只保留第 2,3 行
# 第二个索引表明取全部元素
a[1:3,:] # [[12 13 14 15 16 17]
# [18 19 20 21 22 23]]
对于 N 维数组,跟二维数组类似,a[1,2,3, ...]
,有 N 个索引可以使用。
形状操作
最常用的方法还是 reshape()
方法,示例如下:
# 3 行 4 列的矩阵
a = np.arange(12).reshape(3, 4)
# [[0 1 2 3]
# [4 5 6 7]
# [8 9 10 11]]
# 改变成 6 行 2 列的矩阵
a = a.reshape(6, 2)
# [[0 1]
# [2 3]
# [4 5]
# [6 7]
# [8 9]
# [10 11]]
# 改变成 2x3x2 的三维数组
a = a.reshape(2, 3, 2)
# [[[0 1]
# [2 3]
# [4 5]]
# [[6 7]
# [8 9]
# [10 11]]]
还可以用 ravel()
方法将多维数组展开为 1 维数组,即列表:
# 2x3x2 的三维数组
a = np.arange(12).reshape(2, 3, 2)
# 展开为一维数组
a = a.ravel()
# [0 1 2 3 4 5 6 7 8 9 10 11]
ndarray 中还有一个 T
的属性,可以获得该矩阵的转置:
# 3 行 4 列的矩阵
a = np.arange(12).reshape(3, 4)
# 输出 a 的转置
print(a.T)
# [[0 4 8]
# [1 5 9]
# [2 6 10]
# [3 7 11]]
# 变成 4 行 3 列的了,元素也转置了
相比于 reshape()
只能返回一个修改后的数组,resize()
方法可以直接修改当前的数组,不用接受返回值,如下示例:
# 3 行 4 列的矩阵
a = np.arange(12).reshape(3, 4)
# 以下两句代码的作用是相同的
a = a.reshape(4, 3)
a.resize(4, 3)
# 打印 a
print(a)
拼接和分离数组
拼接
垂直拼接
np.vstack()
水平拼接
np.hstack()
分离
垂直分离
np.vsplit()
水平分离
np.hsplit()
数组拷贝
类似 Python 中的对象,以下代码并不能直接复制数组:
a = np.arange(12).reshape(3, 4)
b = a
# a 和 b 实际是相同的
print(a is bs)
# True
浅拷贝
浅拷贝并不复制里面的元素,也就是说两个变量共享里面的元素,如下示例:
a = np.arange(12).reshape(3, 4)
# b 是 a 的浅拷贝
b = a.view()
# b 中的元素不是自己的
print(b.flags.owndata)
# False
# b 改变形状并不会影响 a
b.resize((4,3))
print(b)
# [[0 1 2]
# [3 4 5]
# [6 7 8]
# [9 10 11]]
print(a)
# [[0 1 2 3]
# [4 5 6 7]
# [8 9 10 11]]
# 但是改变 b 中的元素会影响 a 的元素
b[0, 0] = 100
print(a)
# [[100 1 2 3]
# [4 5 6 7]
# [8 9 10 11]]
深拷贝
使用 copy()
方法可以完全拷贝里面的所有元素,让他们成为两个完全独立的变量:
a = np.arange(12).reshape(3, 4)
b = a.copy()
# 此时无论 b 中元素怎么改变都不会影响 a 的任何元素