What is NumPy?¶
NumPy是Python中科学计算的基本包。它是一个Python库,它提供了一个多维数组对象,各种派生对象(例如屏蔽的数组和矩阵)以及一系列用于数组快速操作的例程,包括数学,逻辑,形状操作,排序,选择,I / O ,离散傅立叶变换,基本线性代数,基本统计操作,随机模拟等等。
NumPy包的核心是ndarray对象。这封装了同质数据类型的n维数组,在编译代码中执行许多操作以实现性能。NumPy数组和标准Python序列之间有几个重要的区别:
- NumPy数组在创建时有固定的大小,不同于Python列表(可以动态增长)。更改ndarray的大小将创建一个新的数组并删除原始数据。
- NumPy数组中的元素都需要具有相同的数据类型,因此在存储器中将具有相同的大小。异常:可以有(Python,包括NumPy)对象的数组,从而允许不同大小的元素的数组。
- NumPy数组便于对大量数据进行高级数学和其他类型的操作。通常,这样的操作比使用Python的内置序列可能更有效和更少的代码执行。
- 越来越多的科学和数学的基于Python的包使用NumPy数组;虽然这些通常支持Python序列输入,它们在处理之前将这些输入转换为NumPy数组,并且它们经常输出NumPy数组。换句话说,为了有效地使用今天的科学/数学基于Python的软件,只是知道如何使用Python的内置序列类型是不够的 - 还需要知道如何使用NumPy数组。
关于序列大小和速度的点在科学计算中特别重要。作为一个简单的例子,考虑将1-D序列中的每个元素与相同长度的另一个序列中的相应元素相乘的情况。如果数据存储在两个Python列表中,a
和b
,我们可以遍历每个元素:
c = []
for i in range(len(a)):
c.append(a[i]*b[i])
这产生正确的答案,但如果a
和b
每个包含数百万个数字,我们将为Python循环的低效率付出代价。我们可以通过编写在C中更快地完成相同的任务(为了清楚起见,我们忽略了变量声明和初始化,内存分配等)
for (i = 0; i < rows; i++): {
c[i] = a[i]*b[i];
}
这节省了解释Python代码和操纵Python对象所涉及的所有开销,但是牺牲了从Python编码中获得的好处。此外,所需的编码工作随着我们的数据的维数而增加。例如,在2-D数组的情况下,C代码(如前所述)扩展为
for (i = 0; i < rows; i++): {
for (j = 0; j < columns; j++): {
c[i][j] = a[i][j]*b[i][j];
}
}
NumPy为我们提供了两个世界中最好的:当涉及到ndarray时,逐个元素操作是“默认模式”,但是逐个元素操作由预编译的C码。在NumPy
c = a * b
做前面的例子做的,以接近C的速度,但代码简单我们期望从基于Python的东西。事实上,NumPy的惯用语法更简单!最后一个例子说明了NumPy的两个特性,它们是它的大部分功能的基础:矢量化和广播。
矢量化描述了在代码中没有任何显式循环,索引等 - 这些事情发生,当然,只是在优化的,预编译的C代码的“幕后”。矢量化代码有很多优点,其中包括:
- 矢量化代码更简洁,更容易阅读
- 更少的代码行通常意味着更少的错误
- 该代码更接近地类似于标准数学符号(使得更容易,通常,以正确地编码数学构造)
- 矢量化导致更多的“Pythonic”代码。如果没有向量化,我们的代码将会效率很低,难以读取
for
循环。
广播是用于描述操作的隐式逐个元素行为的术语;一般来说,在NumPy中,所有操作,不仅仅是算术运算,而是逻辑,逐位,功能等,以这种隐含的逐个元素的方式表现,即它们广播。此外,在上面的示例中,a
和b
可以是相同形状的多维数组,或标量和数组,或甚至具有不同形状的两个阵列,较小的数组“可扩展”为较大数字的形状,使得所得广播是明确的。有关广播的“规则”的详细信息,请参阅numpy.doc.broadcasting
。
NumPy完全支持一种面向对象的方法,再次使用ndarray开始。例如,ndarray是一个类,拥有众多方法和属性。它的许多方法镜像在最外部的NumPy命名空间中的函数,给程序员完全自由的代码,无论哪个范例,她喜欢和/或看起来最适合于手头的任务。