# 什么是NumPy

* [NumPy 是什么？](#numpy-是什么)

## NumPy 是什么？

> 原文：[What is NumPy?](http://docs.scipy.org/doc/numpy-dev/user/whatisnumpy.html)

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 中，我们可以这样遍历每个元素：

```python
c = []
for i in range(len(a)):
    c.append(a[i]*b[i])
```

这就产生了正确的答案，但如果 a 和 b 都含有数以百万计的数字，我们将为Python的低效循环付出代价。我们可以这样以C语言编写代码来完成同样的任务（为清楚起见我们忽略变量声明和初始化、内存分配等）：

```c
for (i = 0; i < rows; i++): {
  c[i] = a[i]*b[i];
}
```

这节省了所有涉及解释Python代码和操作Python对象的开销，但没有了使用Python编码的优势。此外，编码所需的工作量随数据维数的增加而增加。例如对于一个二维数组，C代码（像上面一样简写）会扩展为：

```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中：

```python
c = a * b
```

的行为像之前的例子一样，几近于C语言的速度，但是代码正如我们期望中的那样，就像标准的Python一样简洁。实际上，NumPy的风格还能更简洁！最后这个例子说明了NumPy的两个特性：向量化（Vectorization）和广播（Broadcasting），它们是NumPy强大之处的基础。

向量化用于描述任何缺失的显式循环、索引及其它，在代码这些事情是即时发生的，当然，是在“幕后”（预编译的C代码中）优化。向量化编码的优点很多，比如：

* 向量化的代码更简洁易读
* 代码更少一般意味着更少的错误
* 代码更像标准的数学符号（通常情况下，更容易编写数学结构）
* 向量化的结果更加“Pythonic”。没有向量化，我们的代码会更加低效，循环也难以阅读。

广播是描述隐式的元素级操作的术语；一般来说，NumPy中所有操作，并不只是算术运算，还有逻辑运算，位运算，函数运算等，以这种隐式的元素层面的方式执行，就是广播。此外，在上面的例子中，a 和 b 可以是相同形状的多维数组，或者一个标量和一个数组；甚至可以是不同的形状的2个数组，假设较小的数组可以以产生明确广播的方式，扩展为较大数组的尺寸。详细规则见 [numpy.doc.broadcasting](http://docs.scipy.org/doc/numpy-dev/user/basics.broadcasting.html#module-numpy.doc.broadcasting)。

NumPy完全支持ndarray的面向对象。例如，ndarray是一个类，拥有许多方法和属性。它的许多方法复制了NumPy最外层命名空间的函数，让程序员完全自由决定代码写成哪个范式，以及哪个范式更适合当前的任务。
