numpy

什麼是 NumPy

NumPy是Python中科學計算的基礎包。它是一個Python庫,提供多維數組對象,各類派生對象(如掩碼數組和矩陣),以及用於數組快速操做的各類API,有包括數學、邏輯、形狀操做、排序、選擇、輸入輸出、離散傅立葉變換、基本線性代數,基本統計運算和隨機模擬等等。html

NumPy包的核心是 ndarray 對象。它封裝了python原生的同數據類型的 n 維數組,爲了保證其性能優良,其中有許多操做都是代碼在本地進行編譯後執行的。python

NumPy數組 和 原生Python Array(數組)之間有幾個重要的區別:數組

  • NumPy 數組在建立時具備固定的大小,與Python的原生數組對象(能夠動態增加)不一樣。更改ndarray的大小將建立一個新數組並刪除原來的數組。
  • NumPy 數組中的元素都須要具備相同的數據類型,所以在內存中的大小相同。 例外狀況:Python的原生數組裏包含了NumPy的對象的時候,這種狀況下就容許不一樣大小元素的數組。
  • NumPy 數組有助於對大量數據進行高級數學和其餘類型的操做。一般,這些操做的執行效率更高,比使用Python原生數組的代碼更少。
  • 愈來愈多的基於Python的科學和數學軟件包使用NumPy數組; 雖然這些工具一般都支持Python的原生數組做爲參數,但它們在處理以前會仍是會將輸入的數組轉換爲NumPy的數組,並且也一般輸出爲NumPy數組。換句話說,爲了高效地使用當今科學/數學基於Python的工具(大部分的科學計算工具),你只知道如何使用Python的原生數組類型是不夠的 - 還須要知道如何使用 NumPy 數組。

基礎知識

屬性

  • ndarray.ndim - 數組的軸(維度)的個數。在Python世界中,維度的數量被稱爲rank。
  • ndarray.shape - 數組的維度。這是一個整數的元組,表示每一個維度中數組的大小。對於有 n 行和 m 列的矩陣,shape 將是 (n,m)。所以,shape 元組的長度就是rank或維度的個數 ndim
  • ndarray.size - 數組元素的總數。這等於 shape 的元素的乘積。
  • ndarray.dtype - 一個描述數組中元素類型的對象。可使用標準的Python類型建立或指定dtype。另外NumPy提供它本身的類型。例如numpy.int3二、numpy.int16和numpy.float64。
  • ndarray.itemsize - 數組中每一個元素的字節大小。例如,元素爲 float64 類型的數組的 itemsize 爲8(=64/8),而 complex32 類型的數組的 itemsize 爲4(=32/8)。它等於 ndarray.dtype.itemsize 。
  • ndarray.data - 該緩衝區包含數組的實際元素。一般,咱們不須要使用此屬性,由於咱們將使用索引訪問數組中的元素。

 一個例子less

>>> import numpy as np
>>> a = np.arange(15).reshape(3, 5)
>>> a
array([[ 0,  1,  2,  3,  4],
       [ 5,  6,  7,  8,  9],
       [10, 11, 12, 13, 14]])
>>> a.shape
(3, 5)
>>> a.ndim
2
>>> a.dtype.name
'int64'
>>> a.itemsize
8
>>> a.size
15
>>> type(a)
<type 'numpy.ndarray'>
>>> b = np.array([6, 7, 8])
>>> b
array([6, 7, 8])
>>> type(b)
<type 'numpy.ndarray'>

 

數組建立

有幾種方法能夠建立數組。dom

例如,你可使用array函數從常規Python列表或元組中建立數組。獲得的數組的類型是從Python列表中元素的類型推導出來的。ide

>>> import numpy as np
>>> a = np.array([2,3,4])
>>> a
array([2, 3, 4])
>>> a.dtype
dtype('int64')
>>> b = np.array([1.2, 3.5, 5.1])
>>> b.dtype
dtype('float64')

 

 能夠在建立時顯式指定數組的類型:函數

>>> c = np.array( [ [1,2], [3,4] ], dtype=complex )
>>> c
array([[ 1.+0.j,  2.+0.j],
       [ 3.+0.j,  4.+0.j]])

函數zeros建立一個由0組成的數組,函數 ones建立一個完整的數組,函數empty 建立一個數組,其初始內容是隨機的,取決於內存的狀態。默認狀況下,建立的數組的dtype是 float64 類型的。工具

>>> np.zeros( (3,4) )
array([[ 0.,  0.,  0.,  0.],
       [ 0.,  0.,  0.,  0.],
       [ 0.,  0.,  0.,  0.]])
>>> np.ones( (2,3,4), dtype=np.int16 )                # dtype can also be specified
array([[[ 1, 1, 1, 1],
        [ 1, 1, 1, 1],
        [ 1, 1, 1, 1]],
       [[ 1, 1, 1, 1],
        [ 1, 1, 1, 1],
        [ 1, 1, 1, 1]]], dtype=int16)
>>> np.empty( (2,3) )                                 # uninitialized, output may vary
array([[  3.73603959e-262,   6.02658058e-154,   6.55490914e-260],
       [  5.30498948e-313,   3.14673309e-307,   1.00000000e+000]])

爲了建立數字組成的數組,NumPy提供了一個相似於range的函數,該函數返回數組而不是列表。佈局

>>> np.arange( 10, 30, 5 )
array([10, 15, 20, 25])
>>> np.arange( 0, 2, 0.3 )                 # it accepts float arguments
array([ 0. ,  0.3,  0.6,  0.9,  1.2,  1.5,  1.8])

 

打印數組

當您打印數組時,NumPy以與嵌套列表相似的方式顯示它,但具備如下佈局:性能

  • 最後一個軸從左到右打印,
  • 倒數第二個從上到下打印,
  • 其他部分也從上到下打印,每一個切片用空行分隔。

而後將一維數組打印爲行,將二維數據打印爲矩陣,將三維數據打印爲矩數組表。

>>> a = np.arange(6)                         # 1d array
>>> print(a)
[0 1 2 3 4 5]
>>>
>>> b = np.arange(12).reshape(4,3)           # 2d array
>>> print(b)
[[ 0  1  2]
 [ 3  4  5]
 [ 6  7  8]
 [ 9 10 11]]
>>>
>>> c = np.arange(24).reshape(2,3,4)         # 3d array
>>> print(c)
[[[ 0  1  2  3]
  [ 4  5  6  7]
  [ 8  9 10 11]]
 [[12 13 14 15]
  [16 17 18 19]
  [20 21 22 23]]]

 

基本操做

數組上的算術運算符會應用到 元素 級別。下面是建立一個新數組並填充結果的示例:

>>> a = np.array( [20,30,40,50] )
>>> b = np.arange( 4 )
>>> b
array([0, 1, 2, 3])
>>> c = a-b
>>> c
array([20, 29, 38, 47])
>>> b**2
array([0, 1, 4, 9])
>>> 10*np.sin(a)
array([ 9.12945251, -9.88031624,  7.4511316 , -2.62374854])
>>> a<35
array([ True, True, False, False])

與許多矩陣語言不一樣,乘積運算符*在NumPy數組中按元素進行運算。矩陣乘積可使用@運算符(在python> = 3.5中)或dot函數或方法執行:

>>> A = np.array( [[1,1],
...             [0,1]] )
>>> B = np.array( [[2,0],
...             [3,4]] )
>>> A * B                       # elementwise product
array([[2, 0],
       [0, 4]])
>>> A @ B                       # matrix product
array([[5, 4],
       [3, 4]])
>>> A.dot(B)                    # another matrix product
array([[5, 4],
       [3, 4]])

 

 某些操做(例如+=和 *=)會更直接更改被操做的矩陣數組而不會建立新矩陣數組。

>>> a = np.ones((2,3), dtype=int)
>>> b = np.random.random((2,3))
>>> a *= 3
>>> a
array([[3, 3, 3],
       [3, 3, 3]])
>>> b += a
>>> b
array([[ 3.417022  ,  3.72032449,  3.00011437],
       [ 3.30233257,  3.14675589,  3.09233859]])
>>> a += b                  # b is not automatically converted to integer type
Traceback (most recent call last):
  ...
TypeError: Cannot cast ufunc add output from dtype('float64') to dtype('int64') with casting rule 'same_kind'

許多一元操做,例如計算數組中全部元素的總和,都是做爲ndarray類的方法實現的。

>>> a = np.random.random((2,3))
>>> a
array([[ 0.18626021,  0.34556073,  0.39676747],
       [ 0.53881673,  0.41919451,  0.6852195 ]])
>>> a.sum()
2.5718191614547998
>>> a.min()
0.1862602113776709
>>> a.max()
0.6852195003967595

默認狀況下,這些操做適用於數組,就像它是一個數字列表同樣,不管其形狀如何。可是,經過指定axis 參數,您能夠沿數組的指定軸應用操做:

>>> b = np.arange(12).reshape(3,4)
>>> b
array([[ 0,  1,  2,  3],
       [ 4,  5,  6,  7],
       [ 8,  9, 10, 11]])
>>>
>>> b.sum(axis=0)                            # sum of each column
array([12, 15, 18, 21])
>>>
>>> b.min(axis=1)                            # min of each row
array([0, 4, 8])
>>>
>>> b.cumsum(axis=1)                         # cumulative sum along each row
array([[ 0,  1,  3,  6],
       [ 4,  9, 15, 22],
       [ 8, 17, 27, 38]])

 

通函數

NumPy提供熟悉的數學函數,例如sin,cos和exp。在NumPy中,這些被稱爲「通函數」(ufunc)。在NumPy中,這些函數在數組上按元素進行運算,產生一個數組做爲輸出。

>>> B = np.arange(3)
>>> B
array([0, 1, 2])
>>> np.exp(B)
array([ 1.        ,  2.71828183,  7.3890561 ])
>>> np.sqrt(B)
array([ 0.        ,  1.        ,  1.41421356])
>>> C = np.array([2., -1., 4.])
>>> np.add(B, C)
array([ 2.,  0.,  6.])

 

索引、切片和迭代

一維的數組能夠進行索引、切片和迭代操做的,就像 列表 和其餘Python序列類型同樣。

>>> a = np.arange(10)**3
>>> a
array([  0,   1,   8,  27,  64, 125, 216, 343, 512, 729])
>>> a[2]
8
>>> a[2:5]
array([ 8, 27, 64])
>>> a[:6:2] = -1000    # equivalent to a[0:6:2] = -1000; from start to position 6, exclusive, set every 2nd element to -1000
>>> a
array([-1000,     1, -1000,    27, -1000,   125,   216,   343,   512,   729])
>>> a[ : :-1]                                 # reversed a
array([  729,   512,   343,   216,   125, -1000,    27, -1000,     1, -1000])
>>> for i in a:
...     print(i**(1/3.))
...
nan
1.0
nan
3.0
nan
5.0
6.0
7.0
8.0
9.0

 

多維的數組每一個軸能夠有一個索引。這些索引以逗號​​分隔的元組給出:

>>> def f(x,y):
...     return 10*x+y
...
>>> b = np.fromfunction(f,(5,4),dtype=int)
>>> b
array([[ 0,  1,  2,  3],
       [10, 11, 12, 13],
       [20, 21, 22, 23],
       [30, 31, 32, 33],
       [40, 41, 42, 43]])
>>> b[2,3]
23
>>> b[0:5, 1]                       # each row in the second column of b
array([ 1, 11, 21, 31, 41])
>>> b[ : ,1]                        # equivalent to the previous example
array([ 1, 11, 21, 31, 41])
>>> b[1:3, : ]                      # each column in the second and third row of b
array([[10, 11, 12, 13],
       [20, 21, 22, 23]])

當提供的索引少於軸的數量時,缺失的索引被認爲是完整的切片:

>>> b[-1]                                  # the last row. Equivalent to b[-1,:]
array([40, 41, 42, 43])

b[i] 方括號中的表達式 i 被視爲後面緊跟着 : 的多個實例,用於表示剩餘軸。NumPy也容許你使用三個點寫爲 b[i,...]

三個點( ... )表示產生完整索引元組所需的冒號。例如,若是 x 是rank爲的5數組(即,它具備5個軸),則:

  • x[1,2,...] 至關於 x[1,2,:,:,:]
  • x[...,3] 等效於 x[:,:,:,:,3]
  • x[4,...,5,:] 等效於 x[4,:,:,5,:]
>>> c = np.array( [[[  0,  1,  2],               # a 3D array (two stacked 2D arrays)
...                 [ 10, 12, 13]],
...                [[100,101,102],
...                 [110,112,113]]])
>>> c.shape
(2, 2, 3)
>>> c[1,...]                                   # same as c[1,:,:] or c[1]
array([[100, 101, 102],
       [110, 112, 113]])
>>> c[...,2]                                   # same as c[:,:,2]
array([[  2,  13],
       [102, 113]])

對多維數組進行 迭代(Iterating) 是相對於第一個軸完成的:

>>> for row in b:
...     print(row)
...
[0 1 2 3]
[10 11 12 13]
[20 21 22 23]
[30 31 32 33]
[40 41 42 43]

可是,若是想要對數組中的每一個元素執行操做,可使用flat屬性,該屬性是數組的全部元素的迭代器:

>>> for element in b.flat:
...     print(element)
...
0
1
2
3
10
11
12
13
20
21
22
23
30
31
32
33
40
41
42
43

 

形狀操縱

改變數組的形狀

一個數組的形狀是由每一個軸的元素數量決定的:

>>> a = np.floor(10*np.random.random((3,4)))
>>> a
array([[ 2.,  8.,  0.,  6.],
       [ 4.,  5.,  1.,  1.],
       [ 8.,  9.,  3.,  6.]])
>>> a.shape
(3, 4)

可使用各類命令更改數組的形狀。請注意,如下三個命令都返回一個修改後的數組,但不會更改原始數組:

>>> a.ravel()  # returns the array, flattened
array([ 2.,  8.,  0.,  6.,  4.,  5.,  1.,  1.,  8.,  9.,  3.,  6.])
>>> a.reshape(6,2)  # returns the array with a modified shape
array([[ 2.,  8.],
       [ 0.,  6.],
       [ 4.,  5.],
       [ 1.,  1.],
       [ 8.,  9.],
       [ 3.,  6.]])
>>> a.T  # returns the array, transposed
array([[ 2.,  4.,  8.],
       [ 8.,  5.,  9.],
       [ 0.,  1.,  3.],
       [ 6.,  1.,  6.]])
>>> a.T.shape
(4, 3)
>>> a.shape
(3, 4)

 

由 ravel() 產生的數組中元素的順序一般是「C風格」,也就是說,最右邊的索引「變化最快」,所以[0,0]以後的元素是[0,1] 。若是將數組從新整形爲其餘形狀,則該數組將被視爲「C風格」。NumPy一般建立按此順序存儲的數組,所以 ravel() 一般不須要複製其參數,但若是數組是經過獲取另外一個數組的切片或使用不常見的選項建立的,則可能須要複製它。還可使用可選參數指示函數 ravel() 和 reshape(),以使用FORTRAN樣式的數組,其中最左邊的索引變化最快。

reshape函數返回帶有修改形狀的參數,而該 ndarray.resize方法會修改數組自己:

>>> a
array([[ 2.,  8.,  0.,  6.],
       [ 4.,  5.,  1.,  1.],
       [ 8.,  9.,  3.,  6.]])
>>> a.resize((2,6))
>>> a
array([[ 2.,  8.,  0.,  6.,  4.,  5.],
       [ 1.,  1.,  8.,  9.,  3.,  6.]])

若是在 reshape 操做中將 size 指定爲-1,則會自動計算其餘的 size 大小:

>>> a.reshape(3,-1)
array([[ 2.,  8.,  0.,  6.],
       [ 4.,  5.,  1.,  1.],
       [ 8.,  9.,  3.,  6.]])

 

將不一樣數組堆疊在一塊兒

幾個數組能夠沿不一樣的軸堆疊在一塊兒,例如:

>>> a = np.floor(10*np.random.random((2,2)))
>>> a
array([[ 8.,  8.],
       [ 0.,  0.]])
>>> b = np.floor(10*np.random.random((2,2)))
>>> b
array([[ 1.,  8.],
       [ 0.,  4.]])
>>> np.vstack((a,b))
array([[ 8.,  8.],
       [ 0.,  0.],
       [ 1.,  8.],
       [ 0.,  4.]])
>>> np.hstack((a,b))
array([[ 8.,  8.,  1.,  8.],
       [ 0.,  0.,  0.,  4.]])

 

將一個數組拆分紅幾個較小的數組

使用hsplit,能夠沿數組的水平軸拆分數組,方法是指定要返回的形狀相等的數組的數量,或者指定應該在其以後進行分割的列:

>>> a = np.floor(10*np.random.random((2,12)))
>>> a
array([[ 9.,  5.,  6.,  3.,  6.,  8.,  0.,  7.,  9.,  7.,  2.,  7.],
       [ 1.,  4.,  9.,  2.,  2.,  1.,  0.,  6.,  2.,  2.,  4.,  0.]])
>>> np.hsplit(a,3)   # Split a into 3
[array([[ 9.,  5.,  6.,  3.],
       [ 1.,  4.,  9.,  2.]]), array([[ 6.,  8.,  0.,  7.],
       [ 2.,  1.,  0.,  6.]]), array([[ 9.,  7.,  2.,  7.],
       [ 2.,  2.,  4.,  0.]])]
>>> np.hsplit(a,(3,4))   # Split a after the third and the fourth column
[array([[ 9.,  5.,  6.],
       [ 1.,  4.,  9.]]), array([[ 3.],
       [ 2.]]), array([[ 6.,  8.,  0.,  7.,  9.,  7.,  2.,  7.],
       [ 2.,  1.,  0.,  6.,  2.,  2.,  4.,  0.]])]

 

vsplit沿垂直軸分割,並array_split容許指定要分割的軸。

 

拷貝和視圖

當計算和操做數組時,有時會將數據複製到新數組中,有時則不會。這一般是初學者混淆的根源。有三種狀況:

徹底不復制

簡單分配不會複製數組對象或其數據。

>>> a = np.arange(12)
>>> b = a            # no new object is created
>>> b is a           # a and b are two names for the same ndarray object
True
>>> b.shape = 3,4    # changes the shape of a
>>> a.shape
(3, 4)

Python將可變對象做爲引用傳遞,所以函數調用不會複製。

>>> def f(x):
...     print(id(x))
...
>>> id(a)                           # id is a unique identifier of an object
148293216
>>> f(a)
148293216

視圖或淺拷貝

不一樣的數組對象能夠共享相同的數據。該view方法建立一個查看相同數據的新數組對象。

>>> c = a.view()
>>> c is a
False
>>> c.base is a                        # c is a view of the data owned by a
True
>>> c.flags.owndata
False
>>>
>>> c.shape = 2,6                      # a's shape doesn't change
>>> a.shape
(3, 4)
>>> c[0,4] = 1234                      # a's data changes
>>> a
array([[   0,    1,    2,    3],
       [1234,    5,    6,    7],
       [   8,    9,   10,   11]])

切片數組會返回一個視圖

>>> s = a[ : , 1:3]     # spaces added for clarity; could also be written "s = a[:,1:3]"
>>> s[:] = 10           # s[:] is a view of s. Note the difference between s=10 and s[:]=10
>>> a
array([[   0,   10,   10,    3],
       [1234,   10,   10,    7],
       [   8,   10,   10,   11]])

深拷貝

copy方法生成數組及其數據的完整副本。

>>> d = a.copy()                          # a new array object with new data is created
>>> d is a
False
>>> d.base is a                           # d doesn't share anything with a
False
>>> d[0,0] = 9999
>>> a
array([[   0,   10,   10,    3],
       [1234,   10,   10,    7],
       [   8,   10,   10,   11]])

有時,若是再也不須要原始數組,則應在切片後調用 copy。例如,假設a是一個巨大的中間結果,最終結果b只包含a的一小部分,那麼在用切片構造b時應該作一個深拷貝:

>>> a = np.arange(int(1e8))
>>> b = a[:100].copy()
>>> del a  # the memory of ``a`` can be released.

若是改成使用 b = a[:100],則 a 由 b 引用,而且即便執行 del a 也會在內存中持久存在。

Less 基礎

廣播(Broadcasting)規則

廣播容許通用功能以有意義的方式處理不具備徹底相同形狀的輸入。

廣播的第一個規則是,若是全部輸入數組不具備相同數量的維度,則將「1」重複地預先添加到較小數組的形狀,直到全部數組具備相同數量的維度。

廣播的第二個規則確保沿特定維度的大小爲1的數組表現爲具備沿該維度具備最大形狀的數組的大小。假定數組元素的值沿着「廣播」數組的那個維度是相同的。

應用廣播規則後,全部數組的大小必須匹配。更多細節能夠在廣播中找到。

花式索引和索引技巧

NumPy提供比常規Python序列更多的索引功能。除了經過整數和切片進行索引以外,正如咱們以前看到的,數組能夠由整數數組和布爾數組索引。

使用索引數組進行索引

>>> a = np.arange(12)**2                       # the first 12 square numbers
>>> i = np.array( [ 1,1,3,8,5 ] )              # an array of indices
>>> a[i]                                       # the elements of a at the positions i
array([ 1,  1,  9, 64, 25])
>>>
>>> j = np.array( [ [ 3, 4], [ 9, 7 ] ] )      # a bidimensional array of indices
>>> a[j]                                       # the same shape as j
array([[ 9, 16],
       [81, 49]])

當索引數組a是多維的時,單個索引數組指的是第一個維度a。如下示例經過使用調色板將標籤圖像轉換爲彩色圖像來顯示此行爲。

>>> palette = np.array( [ [0,0,0],                # black
...                       [255,0,0],              # red
...                       [0,255,0],              # green
...                       [0,0,255],              # blue
...                       [255,255,255] ] )       # white
>>> image = np.array( [ [ 0, 1, 2, 0 ],           # each value corresponds to a color in the palette
...                     [ 0, 3, 4, 0 ]  ] )
>>> palette[image]                            # the (2,4,3) color image
array([[[  0,   0,   0],
        [255,   0,   0],
        [  0, 255,   0],
        [  0,   0,   0]],
       [[  0,   0,   0],
        [  0,   0, 255],
        [255, 255, 255],
        [  0,   0,   0]]])

咱們還能夠爲多個維度提供索引。每一個維度的索引數組必須具備相同的形狀。

>>> a = np.arange(12).reshape(3,4)
>>> a
array([[ 0,  1,  2,  3],
       [ 4,  5,  6,  7],
       [ 8,  9, 10, 11]])
>>> i = np.array( [ [0,1],                        # indices for the first dim of a
...                 [1,2] ] )
>>> j = np.array( [ [2,1],                        # indices for the second dim
...                 [3,3] ] )
>>>
>>> a[i,j]                                     # i and j must have equal shape
array([[ 2,  5],
       [ 7, 11]])
>>>
>>> a[i,2]
array([[ 2,  6],
       [ 6, 10]])
>>>
>>> a[:,j]                                     # i.e., a[ : , j]
array([[[ 2,  1],
        [ 3,  3]],
       [[ 6,  5],
        [ 7,  7]],
       [[10,  9],
        [11, 11]]])

固然,咱們能夠按順序(好比列表)放入ij而後使用列表進行索引。

>>> l = [i,j]
>>> a[l]                                       # equivalent to a[i,j]
array([[ 2,  5],
       [ 7, 11]])

可是,咱們不能經過放入ij放入數組來實現這一點,由於這個數組將被解釋爲索引a的第一個維度。

>>> s = np.array( [i,j] )
>>> a[s]                                       # not what we want
Traceback (most recent call last):
  File "<stdin>", line 1, in ?
IndexError: index (3) out of range (0<=index<=2) in dimension 0
>>>
>>> a[tuple(s)]                                # same as a[i,j]
array([[ 2,  5],
       [ 7, 11]])

使用數組索引的另外一個常見用法是搜索與時間相關的系列的最大值:

>>> time = np.linspace(20, 145, 5)                 # time scale
>>> data = np.sin(np.arange(20)).reshape(5,4)      # 4 time-dependent series
>>> time
array([  20.  ,   51.25,   82.5 ,  113.75,  145.  ])
>>> data
array([[ 0.        ,  0.84147098,  0.90929743,  0.14112001],
       [-0.7568025 , -0.95892427, -0.2794155 ,  0.6569866 ],
       [ 0.98935825,  0.41211849, -0.54402111, -0.99999021],
       [-0.53657292,  0.42016704,  0.99060736,  0.65028784],
       [-0.28790332, -0.96139749, -0.75098725,  0.14987721]])
>>>
>>> ind = data.argmax(axis=0)                  # index of the maxima for each series
>>> ind
array([2, 0, 3, 1])
>>>
>>> time_max = time[ind]                       # times corresponding to the maxima
>>>
>>> data_max = data[ind, range(data.shape[1])] # => data[ind[0],0], data[ind[1],1]...
>>>
>>> time_max
array([  82.5 ,   20.  ,  113.75,   51.25])
>>> data_max
array([ 0.98935825,  0.84147098,  0.99060736,  0.6569866 ])
>>>
>>> np.all(data_max == data.max(axis=0))
True

您還可使用數組索引做爲分配給的目標:

>>> a = np.arange(5)
>>> a
array([0, 1, 2, 3, 4])
>>> a[[1,3,4]] = 0
>>> a
array([0, 0, 2, 0, 0])

可是,當索引列表包含重複時,分配會屢次完成,留下最後一個值:

>>> a = np.arange(5)
>>> a[[0,0,2]]=[1,2,3]
>>> a
array([2, 1, 3, 3, 4])

這是合理的,但請注意是否要使用Python的 +=構造,由於它可能不會按預期執行:

>>> a = np.arange(5)
>>> a[[0,0,2]]+=1
>>> a
array([1, 1, 3, 3, 4])

即便0在索引列表中出現兩次,第0個元素也只增長一次。這是由於Python要求「a + = 1」等同於「a = a + 1」。

 

使用布爾數組進行索引

當咱們使用(整數)索引數組索引數組時,咱們提供了要選擇的索引列表。使用布爾索引,方法是不一樣的; 咱們明確地選擇咱們想要的數組中的哪些項目以及咱們不須要的項目。

人們能夠想到的最天然的布爾索引方法是使用與原始數組具備 相同形狀的 布爾數組:

>>> a = np.arange(12).reshape(3,4)
>>> b = a > 4
>>> b                                          # b is a boolean with a's shape
array([[False, False, False, False],
       [False,  True,  True,  True],
       [ True,  True,  True,  True]])
>>> a[b]                                       # 1d array with the selected elements
array([ 5,  6,  7,  8,  9, 10, 11])

此屬性在分配中很是有用:

>>> a[b] = 0                                   # All elements of 'a' higher than 4 become 0
>>> a
array([[0, 1, 2, 3],
       [4, 0, 0, 0],
       [0, 0, 0, 0]])

您能夠查看如下示例,瞭解如何使用布爾索引生成Mandelbrot集的圖像:

>>> import numpy as np
>>> import matplotlib.pyplot as plt
>>> def mandelbrot( h,w, maxit=20 ):
...     """Returns an image of the Mandelbrot fractal of size (h,w)."""
...     y,x = np.ogrid[ -1.4:1.4:h*1j, -2:0.8:w*1j ]
...     c = x+y*1j
...     z = c
...     divtime = maxit + np.zeros(z.shape, dtype=int)
...
...     for i in range(maxit):
...         z = z**2 + c
...         diverge = z*np.conj(z) > 2**2            # who is diverging
...         div_now = diverge & (divtime==maxit)  # who is diverging now
...         divtime[div_now] = i                  # note when
...         z[diverge] = 2                        # avoid diverging too much
...
...     return divtime
>>> plt.imshow(mandelbrot(400,400))
>>> plt.show()

 

使用布爾值進行索引的第二種方法更相似於整數索引; 對於數組的每一個維度,咱們給出一個1D布爾數組,選擇咱們想要的切片:

>>> a = np.arange(12).reshape(3,4)
>>> b1 = np.array([False,True,True])             # first dim selection
>>> b2 = np.array([True,False,True,False])       # second dim selection
>>>
>>> a[b1,:]                                   # selecting rows
array([[ 4,  5,  6,  7],
       [ 8,  9, 10, 11]])
>>>
>>> a[b1]                                     # same thing
array([[ 4,  5,  6,  7],
       [ 8,  9, 10, 11]])
>>>
>>> a[:,b2]                                   # selecting columns
array([[ 0,  2],
       [ 4,  6],
       [ 8, 10]])
>>>
>>> a[b1,b2]                                  # a weird thing to do
array([ 4, 10])

請注意,1D布爾數組的長度必須與要切片的尺寸(或軸)的長度一致。在前面的例子中,b1具備長度爲3(的數目 的行 中a),和 b2(長度4)適合於索引的第二軸線(列) a

 

ix_()函數

ix_函數可用於組合不一樣的向量,以便得到每一個n-uplet的結果。例如,若是要計算從每一個向量a,b和c中取得的全部三元組的全部a + b * c:

>>> a = np.array([2,3,4,5])
>>> b = np.array([8,5,4])
>>> c = np.array([5,4,6,8,3])
>>> ax,bx,cx = np.ix_(a,b,c)
>>> ax
array([[[2]],
       [[3]],
       [[4]],
       [[5]]])
>>> bx
array([[[8],
        [5],
        [4]]])
>>> cx
array([[[5, 4, 6, 8, 3]]])
>>> ax.shape, bx.shape, cx.shape
((4, 1, 1), (1, 3, 1), (1, 1, 5))
>>> result = ax+bx*cx
>>> result
array([[[42, 34, 50, 66, 26],
        [27, 22, 32, 42, 17],
        [22, 18, 26, 34, 14]],
       [[43, 35, 51, 67, 27],
        [28, 23, 33, 43, 18],
        [23, 19, 27, 35, 15]],
       [[44, 36, 52, 68, 28],
        [29, 24, 34, 44, 19],
        [24, 20, 28, 36, 16]],
       [[45, 37, 53, 69, 29],
        [30, 25, 35, 45, 20],
        [25, 21, 29, 37, 17]]])
>>> result[3,2,4]
17
>>> a[3]+b[2]*c[4]
17

還能夠按以下方式實現reduce:

>>> def ufunc_reduce(ufct, *vectors):
...    vs = np.ix_(*vectors)
...    r = ufct.identity
...    for v in vs:
...        r = ufct(r,v)
...    return r

而後將其用做:

>>> ufunc_reduce(np.add,a,b,c)
array([[[15, 14, 16, 18, 13],
        [12, 11, 13, 15, 10],
        [11, 10, 12, 14,  9]],
       [[16, 15, 17, 19, 14],
        [13, 12, 14, 16, 11],
        [12, 11, 13, 15, 10]],
       [[17, 16, 18, 20, 15],
        [14, 13, 15, 17, 12],
        [13, 12, 14, 16, 11]],
       [[18, 17, 19, 21, 16],
        [15, 14, 16, 18, 13],
        [14, 13, 15, 17, 12]]])

與普通的ufunc.reduce相比,這個版本的reduce的優勢是它利用了廣播規則 ,以免建立一個參數數組,輸出的大小乘以向量的數量。

線性代數

>>> import numpy as np
>>> a = np.array([[1.0, 2.0], [3.0, 4.0]])
>>> print(a)
[[ 1.  2.]
 [ 3.  4.]]

>>> a.transpose()
array([[ 1.,  3.],
       [ 2.,  4.]])

>>> np.linalg.inv(a)
array([[-2. ,  1. ],
       [ 1.5, -0.5]])

>>> u = np.eye(2) # unit 2x2 matrix; "eye" represents "I"
>>> u
array([[ 1.,  0.],
       [ 0.,  1.]])
>>> j = np.array([[0.0, -1.0], [1.0, 0.0]])

>>> j @ j        # matrix product
array([[-1.,  0.],
       [ 0., -1.]])

>>> np.trace(u)  # trace
2.0

>>> y = np.array([[5.], [7.]])
>>> np.linalg.solve(a, y)
array([[-3.],
       [ 4.]])

>>> np.linalg.eig(j)
(array([ 0.+1.j,  0.-1.j]), array([[ 0.70710678+0.j        ,  0.70710678-0.j        ],
       [ 0.00000000-0.70710678j,  0.00000000+0.70710678j]]))
Parameters:
    square matrix
Returns
    The eigenvalues, each repeated according to its multiplicity.
    The normalized (unit "length") eigenvectors, such that the
    column ``v[:,i]`` is the eigenvector corresponding to the
    eigenvalue ``w[i]`` .

技巧和提示

這裏咱們列出一些簡短有用的提示。

「自動」整形

要更改數組的尺寸,您能夠省略其中一個尺寸,而後自動推導出尺寸:

>>> a = np.arange(30)
>>> a.shape = 2,-1,3  # -1 means "whatever is needed"
>>> a.shape
(2, 5, 3)
>>> a
array([[[ 0,  1,  2],
        [ 3,  4,  5],
        [ 6,  7,  8],
        [ 9, 10, 11],
        [12, 13, 14]],
       [[15, 16, 17],
        [18, 19, 20],
        [21, 22, 23],
        [24, 25, 26],
        [27, 28, 29]]])

矢量堆疊

咱們如何從同等大小的行向量列表中構造一個二維數組?在MATLAB這是很簡單:若是xy你只須要作兩個相同長度的向量m=[x;y]。在此NumPy的經過功能的工做原理column_stackdstackhstackvstack,視維在堆疊是必需要作的。例如:

x = np.arange(0,10,2)                     # x=([0,2,4,6,8])
y = np.arange(5)                          # y=([0,1,2,3,4])
m = np.vstack([x,y])                      # m=([[0,2,4,6,8],
                                          #     [0,1,2,3,4]])
xy = np.hstack([x,y])                     # xy =([0,2,4,6,8,0,1,2,3,4])

這些函數背後的邏輯在兩個以上的維度上可能很奇怪。

直方圖

histogram應用於數組的NumPy 函數返回一對向量:數組的直方圖和bin的向量。注意: matplotlib還有一個構建直方圖的功能(hist在Matlab中稱爲),與NumPy中的直方圖不一樣。主要區別在於pylab.hist自動繪製直方圖,而 numpy.histogram只生成數據。

>>> import numpy as np
>>> import matplotlib.pyplot as plt
>>> # Build a vector of 10000 normal deviates with variance 0.5^2 and mean 2
>>> mu, sigma = 2, 0.5
>>> v = np.random.normal(mu,sigma,10000)
>>> # Plot a normalized histogram with 50 bins
>>> plt.hist(v, bins=50, density=1)       # matplotlib version (plot)
>>> plt.show()

 

 

>>> # Compute the histogram with numpy and then plot it
>>> (n, bins) = np.histogram(v, bins=50, density=True)  # NumPy version (no plot)
>>> plt.plot(.5*(bins[1:]+bins[:-1]), n)
>>> plt.show()

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

相關文章
相關標籤/搜索
本站公眾號
   歡迎關注本站公眾號,獲取更多信息