numpy01:数组操作

NumPy简介

NumPy(Numerical Python 的简称)提供了高效存储和操作密集数据缓存的接口。在某些方面,NumPy 数组与 Python 内置的列表类型非常相似。但是随着数组在维度上变大,NumPy 数组提供了更加高效的存储和数据操作。

Python 的列表为了兼顾更多的情况,在运算时需要包含大量的额外信息,这不但占用大量的内存,还会造成遍历、修改与重排的速度都非常缓慢。NumPy 的数组在存储和运算上都比 Python 的列表更加高效。

NumPy 是 Python 在数据科学中最常用,也是最基础的库。后续介绍的许多科学计算库,都是基于 NumPy 建立的。

可以使用 pip 来安装 NumPy :

$ pip install numpy

安装完成后,可以在命令行中检查是否成功安装,并查看安装的版本:

>>> import numpy >>> numpy.__version__ '1.21.1'

一般来说,工程中使用以下的方式在导入 NumPy 并重命名为 np

import numpy as np

NumPy 的官方网站为 https://numpy.org/ ,从中可以找到 NumPy 的文档以及各种学习资料。

创建数组

构成 numpy 的基础就是它特有的多维数组对象 ndarray 。在介绍如何操作数组对象之前,首先介绍如何创建数组。

从已有数据创建数组

可以使用 array() 函数从 Python 的列表对象创建数组:

np.array([1, 3, 2, 5, 4])
array([1, 3, 2, 5, 4])

不同于 Python 列表,numpy 为了确保数组的一致性,要求数组必须包含同一类型的数据。如果类型不匹配,numpy 将会尝试向上转换。例如,整型被转换为浮点型:

np.array([3.14, 2, 6])
array([3.14, 2. , 6. ])

如果希望明确设置数组的数据类型,可以用 dtype 参数指定:

np.array([1, 2, 3, 4], dtype='float32')
array([1., 2., 3., 4.], dtype=float32)

numpy 可用的数据类型将在之后介绍。

numpy 数组可以被指定为多维的。以下是用嵌套列表从初始化创建多维数组的一种方法:

np.array([range(i, i + 3) for i in [2, 4, 6]])
array([[2, 3, 4], [4, 5, 6], [6, 7, 8]])

内层的列表被当作二维数组的行。

从头创建数组

如果需要创建包含大量有规律数据的数组,用 numpy 内置的函数从头创建数组是一种更高效的方法。

可以使用 zeros(shape) 函数来创建数组,其中的每个元素都是 0 ;或者可以使用 ones(shape) 函数来创建每个元素都是 1 的数组。

以下创建一个长度为 9 的数组,数组的值都是 0 :

np.zeros(9, dtype=int)
np.zeros(9, dtype=int)

还可以使用 full(shape, fill_value) 函数来利用某一数据创建数组,其用法和上面两个函数类似。这些从头创建数组的函数都具有一个参数 shape ,可以通过一个数值指定一维数组的长度,还可以通过元组或列表指定多维数组的形状(数组每个维度的长度)。该参数有时候也写作 size

例如,以下创建了一个 3×4 的浮点型数组,数组的值都是 3.14 :

np.full((3, 4), 3.14)
array([[3.14, 3.14, 3.14, 3.14], [3.14, 3.14, 3.14, 3.14], [3.14, 3.14, 3.14, 3.14]])

除了从单一元素创建数组,也可以按照一定规律创建数组。

可以利用 arange() 函数创建一个数组,它和 Python 内置的 range() 函数类似,都有 startstopstep 三个参数,并且部分参数可以省略:

np.arange(0, 14, 2)
array([ 0, 2, 4, 6, 8, 10, 12])

linspace() 函数与之类似,只不过它包含起点和终点,第三个参数是数组元素个数,以此自动分割区间并计算步长:

np.linspace(0, 2, 5)
array([0. , 0.5, 1. , 1.5, 2. ])

随机数数组

numpyrandom 模块提供了随机数函数,可以用于创建随机数组。

np.random 模块和 Python 标准库中的随机数函数具有一定的相似之处,下表列出了 <>np.random 中内容相似的函数:

函数 说明
seed(seed) 设置随机种子
random(size:tuple) 创建在 0~1 范围内的随机小数组成的数组
randint(low, higt, size) 创建范围内随机整数构成的数组。与标准库不同的是,它不包含 high 端点的整数
uniform(low, higt, size) 创建 low~high 范围内的随机小数组成的数组
choice(a, size, replace, p) 按照指定概率从序列中抽取一个元素组成数据,参数 replace 决定是否包含重复元素
shuffle(a) 打乱数组顺序(会改变原数组)

以下是几个简单的示例:

np.random.randint(0, 4, (2, 4))
array([[0, 3, 1, 0], [2, 1, 2, 0]])
np.random.choice(np.arange(10), size=7)
array([6, 9, 1, 0, 1, 8, 8])

除了纯粹随机的数组,numpy 还可以使用 normal(loc, scale, size) 函数来创建一个正态分布的随机数数组,参数 loc 代表均值,scale 代表方差:

np.random.normal(0, 1, (2, 3))
array([[ 0.39728546, 1.07566559, -1.65804868], [ 0.60838938, 1.91130974, 1.40033962]])

或者使用 randn(size) 创建服从标准正态分布的随机数数组。

还可以基于 RandomState 类根据种子创建一个随机的状态,再由该随机状态创建随机数组。这样做可以防止使全局随机状态被污染:

rand = np.random.RandomState(10)
rand.random(5)
array([0.77132064, 0.02075195, 0.63364823, 0.74880388, 0.49850701])

除此之外,还有一些特殊的函数:eye(n) 可以创建一个阶数为 n 的单位矩阵数组:

np.eye(3)
array([[1., 0., 0.], [0., 1., 0.], [0., 0., 1.]])

empty(shape) 可以创建一个空数组,但不初始化,因此得到的元素可能是内存中的任意值。

NumPy数据类型

numpy 数组需要包含同一类型的值。由于 numpy 是在C语言的基础上开发的,因此这些数据类型类似C语言对应的数据类型。

标准的 numpy 数据类型可以在 https://numpy.org/doc/stable/user/basics.types.html 中查到,下表列出了一些比较典型的示例:

数据类型描述
bool_布尔值(真/ True 或假/ False ),用一个字节存储
intc同C语言的 int 相同,且由平台指定具体位数
intp用作索引的整型(和C语言的 ssize_t 相同,且由平台指定具体位数
int88 位整数(字节,范围从 –128 到 127 )
uint16无符号整数(范围从 0 到 65535 )
float3232 位浮点数(1 位符号,8 位指数,23 位尾数)
complex128由两个 64 位浮点数表示的复数

当构建一个数组时,可以用一个字符串参数来指定数据类型:

np.zeros(10, dtype='int16')

或者用相关的 numpy 对象来指定:

np.zeros(10, dtype=np.int16)

还可以使用更高级的数据类型,例如指定高位字节数或低位字节数。numpy 也支持复合数据类型,将在后续介绍。

一个数组的数据类型保存在它的 .dtype 属性中。不过如果要修改数组的数据类型,不能直接修改该属性,而是要调用数组的 .astype() 方法:

arr = np.random.randint(10, size=(2, 4))
arr.astype(np.float32)
array([[2., 6., 0., 9.], [2., 6., 6., 2.]], dtype=float32)

这个操作会得到一个新的数组,不改变原有数组的数据类型。

京ICP备2021034974号
contact me by hello@frozencandles.fun