1.NumPy简介与数组基础计算
1.1 NumPy 简介
NumPy 库是 Python 的一种开源的数值计算扩展,主要用于数组计算。这种工具可用来存储和处理大型矩阵,比 Python 自身的嵌套列表 (nested list structure) 结构要高效得多(该结构也可以用来表示矩阵 (matrix))。在数据处理任务上,NumPy 是 Pandas 一个较好的补充,有更为丰富的计算函数和更快的计算速度。NumPy 包含:
- 一个强大的 N 维数组对象 ndarray
- 广播功能函数
- 整合 C/C++/Fortran 代码的工具
- 线性代数、傅里叶变换、随机数生成等功能
NumPy 导入:
python
conda install numpy # 或 pip3 install numpy
import numpy as np1.2 NumPy 数组基础
1.2.1 创建数组
(1) 创建一维数组
- 打印结果和列表相似
- 使用
np.array方法生成 - 一维数组仅需要使用一对
[] - 该数组的元素数据类型是
int64
python
arr = np.array([1, 2, 3, 4, 5])
arr = np.array([1, 2, 3], dtype='int64') # 创建时指定数据类型(2) 创建多维数组
- 可以认为多维度数组的元素仍然是数组
- 二维数组的元素是 1 维数组
- 根据手写的元素和最终打印结果可以判断数组构成形式
python
arr = np.array([[1, 2], [3, 4]])(3) 快速创建函数
np.ones可以生成元素都为 1 的数组np.zeros生成元素都为 0 的数组np.empty生成数组的元素不为空,为随机产生的数据np.arange生成连续整数数组
python
# 生成元素都为1的数组
arr = np.ones(12)
# 生成元素都为0的数组
arr = np.zeros((4, 4))
# 生成数组的元素不为空,为随机产生的数据
arr = np.empty((2, 3, 4))
# 生成连续整数数组
arr = np.arange(4) # 一维
arr = np.arange(8, 15) # 一维
arr = np.arange(1, 10, 2) # 一维
arr = np.arange(10).reshape(2, 5) # 二维
arr = np.arange(24).reshape(2, 3, 4) # 三维1.2.2 属性函数
python
arr.shape # 数组的形状
arr.ndim # 数组的维数
arr.size # 数组元素的个数
arr.itemsize # 单个元素的字节数
arr.nbytes # 所有元素的总字节数1.2.3 数据类型大全
常用的有 bool、int、uint、float、complex
| 名称 | 描述 |
|---|---|
| bool_ | 布尔型数据类型 (True 或者 False) |
| int_ | 默认的整数类型 (类似于 C 语言中的 long, int32 或 int64) |
| intc | 与 C 的 int 类型一样, 一般是 int32 或 int64 |
| intp | 用于索引的整数类型 (类似于 C 的 ssize_t, 一般情况下仍然是 int32 或 int64) |
| int8 | 字节 (-128 to 127) |
| int16 | 整数 (-32768 to 32767) |
| int32 | 整数 (-2147483648 to 2147483647) |
| int64 | 整数 (-9223372036854775808 to 9223372036854775807) |
| uint8 | 无符号整数 (0 to 255) |
| uint16 | 无符号整数 (0 to 65535) |
| uint32 | 无符号整数 (0 to 4294967295) |
| uint64 | 无符号整数 (0 to 18446744073709551615) |
| float_ | float64 类型的简写 |
| float16 | 半精度浮点数, 包括: 1 个符号位, 5 个指数位, 10 个尾数位 |
| float32 | 单精度浮点数, 包括: 1 个符号位, 8 个指数位, 23 个尾数位 |
| float64 | 双精度浮点数, 包括: 1 个符号位, 11 个指数位, 52 个尾数位 |
| complex_ | complex128 类型的简写, 即 128 位复数 |
| complex64 | 复数, 表示双 32 位浮点数 (实数部分和虚数部分) |
| complex128 | 复数, 表示双 64 位浮点数 (实数部分和虚数部分) |
1.2.4 类型转化
- 类型转化不一定成功
- 有可能出现无法转化并报错的情况,例如复数(complex)无法转化成整型 (int) 和浮点型 (float)
- 即使成功了也要注意数据本身的变化,因为未必和预期一致
python
# 单个字符的转化
np.float64(42)
np.int8(127.0)
np.int8(-128.0)
np.int8(129.0)
np.bool_(42)
np.bool_(0)
np.bool_(42.0)
np.float_(True)
np.float_(False)
np.arange(7, dtype=np.uint16)
# 数组的转化
arr = np.array([5.2, 3.2, 9.96, -3.0, -1.9, 10.81])
arr = arr.astype(np.int32) # [5,3,9,-3,-1,10],-1.9先不看负号进行转换后再加上负号1.2.5 字符编码
- 当需要指定数据类型时,可以通过 字符编码 来实现
- 常用的数据类型包括:整数、浮点数、字符串
| 数据类型 | 字符编码 |
|---|---|
| 整数 | i |
| 无符号整数 | u |
| 单精度浮点数 | f |
| 双精度浮点数 | d |
| 布尔值 | b |
| 复数 | D |
| 字符串 | S |
| Unicode 字符串 | U |
| void(空) | V |
python
np.arange(7, dtype='f') # [0. 1. 2. 3. 4. 5. 6.]
np.arange(7, dtype='D') # [0.+0.j 1.+0.j 2.+0.j 3.+0.j 4.+0.j 5.+0.j 6.+0.j]
np.dtype(float) # float64
np.dtype('f') # float32
np.dtype('d') # float64
np.dtype('D') # complex128
np.dtype('f8') # float64
np.dtype('float64') # float641.3 NumPy 数组计算
1.3.1 四则运算
NumPy数组可以简单地进行四则运算NumPy数组的幂函数运算可以通过**来完成- 可以通过结果和运算的对比来理解运算的处理逻辑
python
# 数组与标量的运算
arr = np.array([[1., 1., 2.], [3., 5., 8.]]) # 定义二维数组
print(arr) # 打印数组
print(arr * arr) # 元素逐位相乘
print('*' * 90) # 打印分隔线
print(arr - arr) # 元素逐位相减
print('*' * 90) # 打印分隔线
print(1 / arr) # 元素逐位求倒数
print('*' * 90) # 打印分隔线
print(arr ** 0.5) # 元素逐位开平方1.3.2 一维数组索引
- 索引可以联想 list 列表的索引规则
- 特别说明:
7:2是选中前 7 个元素,从 0 开始每 2 个选一个 - 可以使用
slice事先写好起始点与步长 - 如果实在理解困难,可以记住规律,以下三个参数分别为开始位置、结束为止和步长
切片格式:start : stop : step
python
# 一维数组的索引与切片
a = np.arange(9) # 生成包含0到8的一维数组
a # 打印数组内容
print(a[0]) # 访问索引0的元素
print(a[3:7]) # 获取索引3到6的元素
print(a[:7:2]) # 从头到索引6每隔2个取一个
print(a[::-1]) # 步长为负实现反转
s = slice(3, 7, 2) # 定义切片对象起点3终点7步长2
print(a[s]) # 使用切片对象取值
s = slice(None, None, -1) # 定义反向切片对象
print(a[s]) # 使用切片对象反转数组1.3.3 多维数组索引
- 考虑多维数组索引结果,要分层理解
- 可参考数组的结构与索引数字来判断结果
- 建议在 notebook 中交互验证
python
# 选取数组元素 索引
a = np.array([[101, 102], [103, 104]]) # 定义二维数组
print(a) # 打印数组
print(a[0, 0]) # 取第0行第0列
print(a[0, 1]) # 取第0行第1列
print(a[1, 0]) # 取第1行第0列
print(a[1, 1]) # 取第1行第1列
# 多维数组的切片与索引
b = np.arange(12).reshape(2, 2, 3) # 创建一个形状为(2,2,3)的三维数组
print(b.shape) # 打印数组形状
print(b) # 打印数组内容
print(b[0, 0, 0]) # 取第0块 第0行 第0列
print(b[:, 0, 0]) # 取所有块中 第0行 第0列1.3.4 数组切片
- 多维数组的索引是按照
,分隔开的 :表示选择全部,::-1表示全部选择后逆向…代表省略(省略的维度上选择全部)
python
b[0] # 取第一层二维数组
b[0, :, :] # 同上,完整二维切片
b[0, …] # 等价于 b[0, :, :]
b[0, 1] # 取第0层的第1行
b[0, 1, ::2] # 取第0层第1行,步长为2的列
b[…, 1] # 取所有二维数组的第1列
b[:, 1] # 取每个二维数组的第1行
b[:, 1, :] # 同上,完整行切片
b[0, :, 1] # 取第0层每行的第1个元素
b[0, :, -1] # 取第0层每行最后一个元素
b[0, ::-1, -1] # 第0层的行反向后取最后一列
b[0, ::2, -1] # 第0层中隔行取最后一列
b[::-1] # 翻转第一个维度(整体上下翻转)
s = slice(None, None, -1)
b[(s, s, s)] # 所有维度反向取值(整体翻转)1.3.5 布尔索引
- 注意数组最后的结果,默认是按行筛选
- 如果知道了布尔数组的索引,可以写成下面的标准形式
- 布尔索引更简洁
python
# 布尔索引
names = np.array(['Bob', 'Joe', 'Will', 'Bob', 'Will', 'Joe', 'Joe']) # 姓名数组
data = np.random.randn(7, 4) # 7 行 4 列随机数
print(names) # 查看 names
print(data) # 查看 data
# 布尔条件判断
print(names == 'Bob') # 判断是否等于 'Bob' 得到布尔数组
print(data[names == 'Bob']) # 使用布尔数组筛选对应行
print(data[(names == 'Bob'), 0]) # 布尔条件筛选行后取第 0 列
# shape 说明
print(data.shape) # 显示 data 的形状 (7,4)
print(names.shape) # 显示 names 的形状 (7,)补充说明:
shape的第一个值都是7,表示有 7 行- 布尔索引使得数据筛选更灵活简洁
1.3.6 花式索引
- 行索引和列索引结合,根据结果判断筛选方式
- 先把布尔值判断的结果赋值,再对数组进行筛选操作
python
# 花式索引
print(data[names == 'Bob', 2]) # 行用布尔判断筛选 'Bob',列取第 2 列
print(data[names == 'Bob', 3]) # 行筛选 'Bob',列取第 3 列
print(names != 'Bob') # 判断不等于 'Bob'
print(data[~(names == 'Bob')]) # 使用取反 ~ 选择不是 Bob 的行
mask = (names == 'Bob') | (names == 'Will') # 组合条件:是 Bob 或 Will
print(mask) # 查看布尔掩码
print(data[mask]) # 使用组合 mask 选择行1.3.7 布尔索引便捷操作
- 数组与数值的比较结果是元素级的,所以索引也是元素级别的
- 选中位置后可以直接进行赋值
python
# 布尔索引便捷操作
data[data < 1] = 100 # 选择所有小于 1 的元素并赋值为 100
print(data) # 查看结果
data[names != 'Joe'] = 7 # 所有名字不是 Joe 的行全部赋值为 7
print(data) # 查看结果