译者:飞龙
1.1 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数组。
序列大小和速度在科学计算中尤为重要。例如考虑两个长度相同的列表中每个元素相乘的情况。如果数据被存储在两个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编码的优势。此外,编码所需的工作量随数据维数的增加而增加。例如对于一个二维数组,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的两个特性:向量化(Vectorization)和广播(Broadcasting),它们是NumPy强大之处的基础。
向量化用于描述任何缺失的显式循环、索引及其它,在代码这些事情是即时发生的,当然,是在“幕后”(预编译的C代码中)优化。向量化编码的优点很多,比如:
向量化的代码更简洁易读
代码更少一般意味着更少的错误
代码更像标准的数学符号(通常情况下,更容易编写数学结构)
向量化的结果更加“Pythonic”。没有向量化,我们的代码会更加低效,循环也难以阅读。
广播是描述隐式的元素级操作的术语;一般来说,NumPy中所有操作,并不只是算术运算,还有逻辑运算,位运算,函数运算等,以这种隐式的元素层面的方式执行,就是广播。此外,在上面的例子中,a 和 b 可以是相同形状的多维数组,或者一个标量和一个数组;甚至可以是不同的形状的2个数组,假设较小的数组可以以产生明确广播的方式,扩展为较大数组的尺寸。详细规则见 numpy.doc.broadcasting。
NumPy完全支持ndarray的面向对象。例如,ndarray是一个类,拥有许多方法和属性。它的许多方法复制了NumPy最外层命名空间的函数,让程序员完全自由决定代码写成哪个范式,以及哪个范式更适合当前的任务。
1.2 安装 NumPy
大多数情况下,在系统上安装NumPy的最好办法是使用为你的操作系统预编译的包。
一些可选的连接请见 http://scipy.org/install.html 。
有关源码包构建的说明,请见从源码中构建。这些信息主要用于高级用户。