3.9 大型数组�算¶

问题¶

你需�在大数�集(比如数组或网格)上�执行计算。

解决方案¶

涉�到数组的��级�算�作,�以使用 NumPy 库。 NumPy 的一个主�特�是它会给Python�供一个数组对象,相比标准的Python列表而已更适�用��数学�算。 下�是一个简�的�例�,�你展示标准列表对象和 NumPy 数组对象之间的差别:

>>> # Python lists
>>> x = [1, 2, 3, 4]
>>> y = [5, 6, 7, 8]
>>> x * 2
[1, 2, 3, 4, 1, 2, 3, 4]
>>> x + 10
Traceback (most recent call last):
    File "<stdin>", line 1, in <module>
TypeError: can only concatenate list (not "int") to list
>>> x + y
[1, 2, 3, 4, 5, 6, 7, 8]

>>> # Numpy arrays
>>> import numpy as np
>>> ax = np.array([1, 2, 3, 4])
>>> ay = np.array([5, 6, 7, 8])
>>> ax * 2
array([2, 4, 6, 8])
>>> ax + 10
array([11, 12, 13, 14])
>>> ax + ay
array([ 6, 8, 10, 12])
>>> ax * ay
array([ 5, 12, 21, 32])
>>>

正如所�,两�方案中数组的基本数学�算结果并�相�。 特别的, NumPy 中的标��算(比如 ax * 2 或 ax + 10 )会作用在�一个元素上。 �外,当两个�作数都是数组的时候执行元素对等�置计算,并最终生�一个新的数组。

对整个数组中所有元素�时执行数学�算�以使得作用在整个数组上的函数�算简�而�快速。 比如,如果你想计算多项�的值,�以这样�:

>>> def f(x):
... return 3*x**2 - 2*x + 7
...
>>> f(ax)
array([ 8, 15, 28, 47])
>>>

NumPy 还为数组�作�供了大�的通用函数,这些函数�以作为 math 模�中类似函数的替代。比如:

>>> np.sqrt(ax)
array([ 1. , 1.41421356, 1.73205081, 2. ])
>>> np.cos(ax)
array([ 0.54030231, -0.41614684, -0.9899925 , -0.65364362])
>>>

使用这些通用函数�比循环数组并使用 math 模�中的函数执行计算�快的多。 因此,��有�能的�尽�选择 NumPy 的数组方案。

底层实现中, NumPy 数组使用了C或者Fortran语言的机制分�内存。 也就是说,它们是一个�常大的连续的并由�类型数�组�的内存区域。 所以,你�以构造一个比普通Python列表大的多的数组。 比如,如果你想构造一个10,000*10,000的浮点数二维网格,很轻�:

>>> grid = np.zeros(shape=(10000,10000), dtype=float)
>>> grid
    array([[ 0., 0., 0., ..., 0., 0., 0.],
    [ 0., 0., 0., ..., 0., 0., 0.],
    [ 0., 0., 0., ..., 0., 0., 0.],
    ...,
    [ 0., 0., 0., ..., 0., 0., 0.],
    [ 0., 0., 0., ..., 0., 0., 0.],
    [ 0., 0., 0., ..., 0., 0., 0.]])
>>>

所有的普通�作还是会�时作用在所有元素上:

>>> grid += 10
>>> grid
array([[ 10., 10., 10., ..., 10., 10., 10.],
    [ 10., 10., 10., ..., 10., 10., 10.],
    [ 10., 10., 10., ..., 10., 10., 10.],
    ...,
    [ 10., 10., 10., ..., 10., 10., 10.],
    [ 10., 10., 10., ..., 10., 10., 10.],
    [ 10., 10., 10., ..., 10., 10., 10.]])
>>> np.sin(grid)
array([[-0.54402111, -0.54402111, -0.54402111, ..., -0.54402111,
        -0.54402111, -0.54402111],
    [-0.54402111, -0.54402111, -0.54402111, ..., -0.54402111,
        -0.54402111, -0.54402111],
    [-0.54402111, -0.54402111, -0.54402111, ..., -0.54402111,
        -0.54402111, -0.54402111],
    ...,
    [-0.54402111, -0.54402111, -0.54402111, ..., -0.54402111,
        -0.54402111, -0.54402111],
    [-0.54402111, -0.54402111, -0.54402111, ..., -0.54402111,
        -0.54402111, -0.54402111],
    [-0.54402111, -0.54402111, -0.54402111, ..., -0.54402111,
        -0.54402111, -0.54402111]])
>>>

关于 NumPy 有一点需�特别的主�,那就是它扩展Python列表的索引功能 - 特别是对于多维数组。 为了说明清楚,先构造一个简�的二维数组并试��些试验:

>>> a = np.array([[1, 2, 3, 4], [5, 6, 7, 8], [9, 10, 11, 12]])
>>> a
array([[ 1, 2, 3, 4],
[ 5, 6, 7, 8],
[ 9, 10, 11, 12]])

>>> # Select row 1
>>> a[1]
array([5, 6, 7, 8])

>>> # Select column 1
>>> a[:,1]
array([ 2, 6, 10])

>>> # Select a subregion and change it
>>> a[1:3, 1:3]
array([[ 6, 7],
        [10, 11]])
>>> a[1:3, 1:3] += 10
>>> a
array([[ 1, 2, 3, 4],
        [ 5, 16, 17, 8],
        [ 9, 20, 21, 12]])

>>> # Broadcast a row vector across an operation on all rows
>>> a + [100, 101, 102, 103]
array([[101, 103, 105, 107],
        [105, 117, 119, 111],
        [109, 121, 123, 115]])
>>> a
array([[ 1, 2, 3, 4],
        [ 5, 16, 17, 8],
        [ 9, 20, 21, 12]])

>>> # Conditional assignment on an array
>>> np.where(a < 10, a, 10)
array([[ 1, 2, 3, 4],
        [ 5, 10, 10, 8],
        [ 9, 10, 10, 10]])
>>>

讨论¶

NumPy 是Python领域中很多科学与工程库的基础,�时也是被广泛使用的最大最��的模�。 �便如此,在刚开始的时候通过一些简�的例�和玩具程�也能帮我们完�一些有趣的事情。

通常我们导入 NumPy 模�的时候会使用语� import numpy as np 。 这样的�你就�用�你的程�里�一��的敲入 numpy ,�需�输入 np 就行了,节�了�少时间。

如果想获�更多的信�,你当然得去 NumPy 官网逛逛了,网�是: http://www.numpy.org