1. 程式人生 > >Python: 大型陣列運算

Python: 大型陣列運算

需要在大資料集(比如陣列或網格) 上面執行計算,涉及到陣列的重量級運算操作,可以使用NumPy 庫。

下面是一個簡單的小例子,展示標準列表物件和NumPy 陣列物件之間的差別

>>> 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]])

>>> 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