概述#
NumPy Logo
Numpy(发音 /ˈnʌmpaɪ/)是一个 Python 语言库,它提供了对大型、多维数组(或称矩阵)的支持,以及大量的操作这些数组的高级数学函数,包括数学、逻辑、形状操作、排序、选择、I/O、离散傅立叶变换、基本线性代数、基本统计运算、随机模拟等等。
前往 NumPy 官方网站,以及 NumPy 中文文档。
NumPy 的特色#
- 强大的多维数组:NumPy 的向量化、索引和广播的理念是当今数组操作事实上的标准,使其变得快速且全功能。
- 数值计算工具:NumPy 提供了各种数学函数、随机数生成器、线性代数例程、傅里叶变换,等等。
- 开源:NumPy 在 BSD 协议下发布,并且在 GitHub 上由一个充满生机、热情和多样化的社区共同维护。
- 可互操作性强:NumPy 支持大量的硬件和计算平台,能很好地分布式、GPU 和稀疏数组库上的计算。
- 易于使用:NumPy 的高级语法让具有各种背景和经验等级的程序员都能掌握和高效使用。
与 MATLAB 比较:
- NumPy 的功能与 MATLAB 类似,他们都是解释执行的,并且都允许用户快速编写针对数组或矩阵的程序。
- MATLAB 的主要优势在于具有大量额外的工具箱,如著名的 Simulink;NumPy 的主要优势是与 Python 完全整合在一起,而 Python 是一个现代的和全功能的编程语言。
- 有大量的 Python 包可以补全 NumPy 的功能,如 SciPy 包补充了许多类似 MATLAB 的函数,Matplotlib 包提供了类似 MATLAB 的绘图功能。
- MATLAB 和 NumPy 都同样依赖 BLAS(基础线性代数程序集,Basic Linear Algebra Subprograms)和LAPACK(线性代数包,Linear Algebra PACKage),从而可以高效地进行线性代数计算。
安装 NumPy?#
如果你使用的包管理工具为 pip,则可以通过如下命令安装 NumPy:
pip install numpy
如果使用 conda,则可以使用如下命令从 defaults 或 conda-forge 频道安装 NumPy:
# 最佳实践,创建一个新环境而不是在基础的 env 环境中安装
conda create -n my-env
conda activate my-env
# 配置从 conda-forge 安装
conda config --env --add channels conda-forge
# 实际的安装命令
conda install numpy
NumPy 数组介绍#
NumPy 包的核心是 ndarray 对象,即 NumPy 数组。该对象封装了相同类型数据构成的多维数组,为了提高性能,许多操作都在编译后的代码中执行。NumPy 数组和标准 Python 序列之间的最重要区别包括:
① NumPy 数组在创建时具有固定的尺寸,不像 Python 列表具有动态的尺寸。改变 ndarray 的尺寸将创建一个新数组,并删除原有数组。
② NumPy 数组的所有元素必须是相同类型的,因此将占据相同尺寸的内存。但有一个例外:NumPy 元素类型可以是 Python 或 NumPy 的数组对象,各个数组可以有不同的元素数量。
③ NumPy 数组擅长对大量数据实施高级的数学或其他类型的操作。与使用 Python 内建的序列相比,这种操作的执行效率更高,代码更少。
④ 越来越多的基于 Python 的科学和数学包都使用 NumPy 数组;虽然这些包通常支持以 Python 序列作为输入,但在运算前都会将输入转换为 NumPy 数组,经常也输出 NumPy 数组。换句话说,为了有效地使用当今许多(甚至可能是大多数)基于 Python 的科学/数学软件,仅仅知道如何使用 Python 的内置序列类型是不够的——还需要知道如何使用 NumPy 数组。
在科学计算中,序列的大小和速度是非常重要的。考虑将一个一维序列中的每个元素与另一个相同长度序列中的对应元素相乘的简单示例,如果将数据都存储在 Python 列表类型变量 a 和 b 中,则应该按照如下方法进行迭代:
a = [x for x in range(100)]
b = [x*x for x in range(100)]
c = []
for i in range(len(a)):
c.append(a[i]*b[i])
这种方法是正确的,但如果 a 和 b 包含数以百万计的元素,这种不断地往 c 中追加元素的效率是极其低下的。在其他一些更偏重底层控制的语言(如 C 语言)中,这种问题却能较容易地被解决。
通过使用 NumPy,在涉及有关 ndarray 类型中需要进行逐个元素遍历操作时,可以按照惯常的 Python 方式操作,同时又以预编译的 C 代码快速执行。对于以上示例,使用 NumPy 后可写作:
import numpy as np
a = np.array([x for x in range(100)])
b = np.array([x*x for x in range(100)])
c = a * b
这行代码所做的事情与前面的代码相同,看上去更简单,但却可以以接近 C 语言的速度执行。这个例子揭示了 NumPy 的两个特征**:矢量化**(vectorization)和广播(broadcasting)——他们是 NumPy 大部分功能的基础。
围绕 ndarray,NumPy 完全支持面向对象的编程方式。ndarray 是一个类,拥有大量方法和属性。它的许多方法都被镜像到 NumPy 命名空间的最外层函数,从而使程序员可以用他们偏爱的范式进行编码。
这种灵活性使 NumPy ndarray 类成为在 Python 中进行多维数据交换的事实标准,NumPy 也成为用 Python 进行科学计算的基础包。
矢量化和广播#
矢量化可以使代码中不出现任何显式的循环和索引,这些是预编译的 C 代码在“幕后”优化的结果。矢量化代码具有如下优点:
- 矢量化代码更简洁,更易于阅读;
- 更少的代码行通常意味着更少的错误;
- 代码更接近于标准的数学符号,因此也更容易基于数学语言编写正确的代码;
- 矢量化使我们更容易编写地道的 Python 风格的代码,避免代码被低效且难以阅读的
for循环弄得一团糟。
广播是用于描述操作以隐式的逐元素进行的术语。一般来说,NumPy 的所有操作,不光算术运算,还包括逻辑、位、功能等,都表现为这种隐式的逐元素进行的行为,即他们进行了广播。此外,在以上示例中,a 和 b 可以是相同形状的多维数组,或者同为标量或同为数组,甚至是不同形状的数组,条件是较小的数组可以“扩展”到更大的形状,以此保证广播能明确无误地进行。