NumPy 快速开始
1. 预备
需要熟悉 Python 基本语法, 同时需要安装 matplotlib 库.
本指南主要介绍 numpy 中的数组. 描述 n 维的表示, 以及如何参与运算. 同时介绍 axis, shape 等属性.
本指南结束后:
- 理解
NumPy中的1维,2维, 以及n维数组. - 不使用循环, 如何进行
n维数组的线性代数运算. - 理解
n维数组的axis与shape属性.
2. 基础
NumPy 的主要对象是齐次 n 维数组 (homogeneous multidimensional array).
- 它是一张元素表, 通常元素是数字.
- 元素的类型均相同.
- 使用非负数字元组作为索引.
在 NumPy 中维度被称为 axes.
例如, 用数组描述一个 3D 空间的点, 可以使用 [1,2,1], 它就有一个轴 (axis), 这个 axis 中含有 3 个元素, 因此我们称其长度是 3. 而下面的示例中, 数组有两个 axes, 第一个 axis 的长度为 2, 第二个 axis 的长度为 3.
[[1., 0., 0.],
[0., 1., 2.]]
所以 轴 的计数 是从外 往内的.
NumPy 的数组类是 ndarray. 也被称为 array. 需要注意的是, 它与 Python 内置的不同. Python 内置的数组仅表示一维数组, 并且功能相对单一. narray 的重要属性有:
| 属性 | 含义 |
|---|---|
ndarray.ndim | 表示数组的轴数(维度). |
ndarray.shape | 表示数组的维度. 它是一个整数元素构成的元组. 其数字表示每一个维度的长度. 例如一个 n 行 m 列的矩阵, 其 shape 就是 (n,m). 而元组元素的个数, 表示轴数 (ndim). |
ndarray.size | 数组中元素的个数, 其值与 shpape 各分量的乘积相等. |
ndarray.dtype | 一个对象, 用于描述数组元素的类型. 可以使用 Python 的类型来指定, 也可以使用 NumPy 提供的类型, 例如 numpy.int16, numpy.int32, 或者 numpy.float64 等. |
ndarray.itemsize | 表示数组中每一个元素的字节大小. 例如一个 float64 的数组, 其每一个元素的字节数为 64/8 为 8, 即 itemsize 为 8. 其值也等于 ndarray.dtype.itemsize. |
ndarray.data | 底层数据的数组表示, 一般不会使用到该属性. 通常会使用索引工具来访问. |
2.1 案例
import numpy as np
a = np.arange(15).reshape(3, 5)
b = np.array([6, 7, 8])
然后依次打印出 a, a.shape, a.ndim, a.dtype.name, a.itemsize, a.size, type(a), 以及 type(b).
reshape函数用来修改数组的shape.
2.2 创建数组
创建数组的方法有很多种. 首先可以基于 Python 的数组来创建, 然后将数组传入 np.array() 方法中得到 ndarray.
常见的错误: 调用
np.array()时, 传入多余1个的参数. 该方法接收数组, 而不是一个个元素.
array 方法可以接收元素为数组的数组, 它自动会将其转换为 高维 数组.
在创建的时候, 可以通过 dtype=类型 来指定元素类型 (问题是哪些类型可以使用).
import numpy as np
a = np.array([2, 3, 4])
b = np.array([(1.5, 2, 3), (4, 5, 6)])
c = np.array([[1, 2], [3, 4]], dtype=complex)
通常数组元素是未知的, 但是元素的个数是可以知道的. 因此 NumPy 提供了一些辅助函数来创建具有占位符的数组. 他们分别是:
| 函数名 | 描述 |
|---|---|
np.zeros(<shape>) | 按照指定 shape 生成数组, 并将元素初始化为 0. |
np.ones(<shape>) | 按照指定 shape 生成数组, 并将元素初始化为 1. |
np.empty(<shape>) | 按照 shape 生成数组, 其元素值为内存中原有值, 不进行初始化. |
元素的类型默认为 float64, 可以在创建时, 通过 dtype= 来指定.
另一个创建 ndarray 的方法是使用 arange 方法. 其参数与用法与 Python 的 range 方法一样.
a = np.arange(10, 30, 5)
b = np.arange(0, 2, 0.3)
当出现浮点数时, 由于计算精度问题, 无法精确计算出生成元素的数量. 因此可以使用 np.linspace() 来指定从 s 到 e 生成 n 个元素. 注意, 生成数据为闭区间.
a = np.linspace(0, 2, 9)
# => array([0. , 0.25, 0.5 , 0.75, 1. , 1.25, 1.5 , 1.75, 2. ])
通常在绘制函数图像时会使用到该函数.
2.3 打印数组
默认数组的打印有一定格式:
- 最后一个轴从左往右打印.
- 倒数第二个轴从上往下打印.
- 其余的轴也是从上往下打印, 并且每一个轴用一个换行区分.
一维打印成行, 二维打印成矩阵, 三维打印成矩阵列表.
如果数组元素非常多, 打印时会忽略内部元素, 仅打印出矩阵边角处的数据.
如果要修改该默认行为, 打印完整数组. 执行下面代码:
np.set_printoptions(threshold=sys.maxsize) # sys module should be imported
2.4 基本运算
- 算术运算会作用到数组的每一个元素上, 并生成一个新的数组作为运算结果.
- 乘法运算 (
*) 有别与其他矩阵语言,NumPy会将矩阵各位置的分量分别进行乘法运算. 要实现矩阵乘法, 可以使用@或.dot()函数 (A @ B或A.dot(B)). - 复合运算符 (
+=,*=等) 则是修改原数组, 而非创建新数组. - 如果参与运算的两个数组类型不一样, 会向上自动转换.
- 大部分一元运算会以方法的形式呈现. 例如聚合函数:
sum(),min(),max()等. - 默认情况下, 所有的运算作用与整个数组, 好比将数组看成一个列表, 依次对列表元素进行操作, 而不会考虑其
shape. 但是指定axis, 那么会沿着该轴来进行运算.
>>> b = np.arange(12).reshape(3, 4)
>>> b
array([[ 0, 1, 2, 3],
[ 4, 5, 6, 7],
[ 8, 9, 10, 11]])
>>>
>>> b.sum(axis=0) # sum of each column
array([12, 15, 18, 21])
>>>
>>> b.min(axis=1) # min of each row
array([0, 4, 8])
>>>
>>> b.cumsum(axis=1) # cumulative sum along each row
array([[ 0, 1, 3, 6],
[ 4, 9, 15, 22],
[ 8, 17, 27, 38]])
关于指定轴对应处理的是什么元素这个比较抽象, 但也比较重要.