1. 程式人生 > >【Python】numpy快速入門

【Python】numpy快速入門

1、基本概念

numpy的主要內容是齊次多維陣列,是一張表,元素型別相同,通常是數字,索引為一個正整數構成的元組。在numpy中,陣列的維叫做axes,axes的個數叫做rank。例如,[1,2,1]是3D空間中的一個座標點,作為陣列,它是一維的,有一個axes,rank的值為1,axes的長度為3。另一個例子,[[1.,0.,0.],[0.,1.,2.]],作為陣列,它是二維的,有兩個axes,rank的值為2,第一維即第一個axes的長度為2,第二維即第二個axes的長度為3。numpy的陣列對應的類為ndarray,別名為array,但numpy.array不同於python標準庫中的類array.array

,後者只處理一維陣列,提供了較少的功能,前者有一些重要的屬性,列舉如下。
ndarray.ndim:陣列的維度或axes個數,也就是rank的值。
ndarray.shape:一個整數構成的的元組,表示陣列中每一維的長度。對於一個n行m列矩陣來說,shape的結果為(n,m)shape的長度即陣列的維度,也就是rank或ndim
ndarray.size:陣列中所有元素的個數,等於shape中元素的乘積。
ndarray.dtype:陣列中元素的資料型別,可以是python標準型別,也可以是numpy提供的型別,如numpy.int16、numpy.int32、numpy.float64。
ndarray.itemsize
:陣列中元素的位元組大小,如元素型別為float64,則itemsize等於64除以8,即8,同理元素型別為complex32itemsize為4,這個值同ndarray.dtype.itemsize
ndarray.data:儲存了陣列元素的buffer,訪問陣列元素時一般使用索引,很少使用這個屬性。

示例——

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

建立陣列——
建立陣列有多種方法。可以使用array函式,引數為python列表或元組,元素型別會自動推導為numpy中的型別,如下例子。

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

一個常見的錯誤是array的引數為多個數字,而不是數字構成的一個列表,如下例子。

>>> a = np.array(1,2,3,4)    # WRONG
>>> a = np.array([1,2,3,4])  # RIGHT

array可以把一個序列的序列轉換為二維陣列,把一個序列的序列的序列轉換為一個三維陣列,依次類推,也就是說序列的元素為另一個序列(包括列表和元組),如下例子。

>>> b = np.array([(1.5,2,3), (4,5,6)])
>>> b
array([[ 1.5,  2. ,  3. ],
       [ 4. ,  5. ,  6. ]])

陣列的元素型別可以在建立時顯式指定,如下例子。

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

許多情況下,陣列中的初始元素是未知的,但我們知道陣列的大小。numpy提供了幾個建立陣列中的元素有預設值的函式,以降低給陣列中的元素賦值的高昂代價。函式zeros建立的陣列中的元素全為0,ones建立的陣列中的元素全為1,empty建立的陣列中的元素為依賴於記憶體狀態的隨機值,它們的資料型別預設為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]])

函式arange用於建立一個數字序列構成的陣列,如下例子。

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

函式arange的引數為浮點數時,由於浮點數的精度有限,一般不可能得到精確的數字,在這種情況下,可以使用linspace獲得我們想要的數字個數,而不是arange中的步進值,如下例子。

>>> from numpy import pi
>>> np.linspace( 0, 2, 9 )                 # 9 numbers from 0 to 2
array([ 0.  ,  0.25,  0.5 ,  0.75,  1.  ,  1.25,  1.5 ,  1.75,  2.  ])
>>> x = np.linspace( 0, 2*pi, 100 )        # useful to evaluate function at lots of points
>>> f = np.sin(x)

列印陣列——
列印陣列時,numpy以巢狀列表的形式進行顯示,最後一個axes的資料從左到右列印,其它的axes的資料從上到下列印。一維陣列列印為行,二維陣列列印為矩陣,三維陣列列印為矩陣的列表,如下例子。

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

如果列印的陣列過大時,numpy預設將不列印陣列的中間內容,如下例子。

>>> print(np.arange(10000))
[   0    1    2 ..., 9997 9998 9999]
>>>
>>> print(np.arange(10000).reshape(100,100))
[[   0    1    2 ...,   97   98   99]
 [ 100  101  102 ...,  197  198  199]
 [ 200  201  202 ...,  297  298  299]
 ...,
 [9700 9701 9702 ..., 9797 9798 9799]
 [9800 9801 9802 ..., 9897 9898 9899]
 [9900 9901 9902 ..., 9997 9998 9999]]

如果想列印陣列的所有內容,可以使用set_printoptions進行設定,如下例子。

>>> np.set_printoptions(threshold='nan')

基本操作——
對陣列進行數學運算時,會作用於每個元素,返回一個新的陣列,如下例子。

>>> 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], dtype=bool)

numpy中陣列通過*進行乘法運算時作用於每個元素,真正的矩陣乘法使用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.dot(B)                    # matrix product
array([[5, 4],
       [3, 4]])
>>> np.dot(A, 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'

型別不同的陣列進行運算時,結果陣列的型別為精度更高的型別,如下例子。

>>> a = np.ones(3, dtype=np.int32)
>>> b = np.linspace(0,pi,3)
>>> b.dtype.name
'float64'
>>> c = a+b
>>> c
array([ 1.        ,  2.57079633,  4.14159265])
>>> c.dtype.name
'float64'
>>> d = np.exp(c*1j)
>>> d
array([ 0.54030231+0.84147098j, -0.84147098+0.54030231j,
       -0.54030231-0.84147098j])
>>> d.dtype.name
'complex128'

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

上面的函式預設把陣列當作一個列表,不考慮陣列的shape,也可以通過函式引數指定axes,如下例子。

>>> 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等,作用於陣列的每個元素,如下例子。

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

多維陣列的每個axes都有一個索引,這些索引組成一個元組,如下例子。

>>> 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後面的所有的預設索引都將作為:進行處理,補全為一個完整的索引元組,另一種寫法是b[i,...]。對於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]])

多維陣列中的迭代器基於第一個axes,如下例子。

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

2、shape操作

修改shape——
陣列的shape中的數字對應於每個axes的元素個數,如下例子。

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

修改陣列shape的方法有多種,它們都不會修改原始陣列,而是返回一個新的陣列,如下例子。

>>> 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風格的,也就是說先處理最右邊的元素,所以a[0,0]後面的元素是a[0,1]。如果陣列從一個shape修改為另一個shape,這個陣列被認為是C風格的。numpy建立陣列時使用了C風格的元素順序,所以ravel不需要拷貝它的引數,但如果陣列來自於另一個數組的切片或使用了特殊的選項,就可能需要進行拷貝。函式ravelreshape還可以通過一個可選的引數指定為FORTRAN風格的陣列,也就是先處理最左邊的元素。reshape返回一個新的陣列,而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.]])

修改shape時,如果一個維的引數值為-1,實際的值將自動計算,如下例子。

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

拼接陣列——
幾個陣列可以根據axes拼接為一個新陣列,如下例子。

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

函式column_stack以列的形式對陣列進行擴充,不同於vstack,如下例子。

>>> from numpy import newaxis
>>> np.column_stack((a,b))   # With 2D arrays
array([[ 8.,  8.,  1.,  8.],
       [ 0.,  0.,  0.,  4.]])
>>> a = np.array([4.,2.])
>>> b = np.array([2.,8.])
>>> a[:,newaxis]  # This allows to have a 2D columns vector
array([[ 4.],
       [ 2.]])
>>> np.column_stack((a[:,newaxis],b[:,newaxis]))
array([[ 4.,  2.],
       [ 2.,  8.]])
>>> np.vstack((a[:,newaxis],b[:,newaxis])) # The behavior of vstack is different
array([[ 4.],
       [ 2.],
       [ 2.],
       [ 8.]])

陣列維數大於2時,hstack拼接陣列時根據第二個axes,vstack拼接陣列時根據第一個axes,concatenate是一個可選引數,指定根據哪個axes進行陣列拼接。r_c_是另一個根據一個axes拼接數字的途徑,可以使用冒號,如下例子。

>>> np.r_[1:4,0,4]
array([1, 2, 3, 0, 4])

引數為陣列時,r_c_類似於vstackhstack的預設行為,不同的是可以通過一個可選引數指定根據哪個axes進行拼接。

拆分陣列——
使用hsplit,可以根據陣列的水平axes拆分陣列,即既可以指定返回的陣列的個數,也可以指定根據哪列進行拆分,如下例子。

>>> 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根據垂直axes拆分陣列,array_split可以指定根據哪個axes進行陣列拆分。

3、拷貝

運算元組時,其中的資料有時要拷貝到另一個數組,有時則不需要,這可能會困擾初學者,下面列舉三種情況。

不拷貝——
簡單賦值不進行拷貝,如下例子。

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

函式的引數為易變物件,不進行拷貝,如下例子。

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

使用切片獲得的新陣列類似於view,如下例子。

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

4、Broadcast

當輸入的陣列的shape不同時,Broadcast以一種有意義的方式去處理這些陣列。規則一,陣列的維度不同時,在維度較小的陣列的shape的前面重複新增數字1,直到陣列的維度相同。規則二,陣列的大小為1時,根據特定的維,其行為好像有最大shape對應的元素個數,元素的值也好像同對應維的陣列的元素值。Broadcast的規則就是保證陣列的大小能夠互相匹配。

5、索引策略

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

對於多維陣列來說,一個索引陣列將參照於多維陣列的第一維,如下例子,使用顏色標籤,通過調色盤,產生一個圖片。

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

索引還可以是多維的,但索引陣列的每一維必須有相同的shape,如下例子。

>>> 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可以放到一個數組中,因為這個陣列將索引目標陣列的第一維,如下例子。

>>> 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, xrange(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])

對於+=這樣的操作符,需要格外注意,結果可能不是我們想要的,如下例子。

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

上面例子中的索引0,雖然出現了兩次,但是第0個元素的值只增加一次。

布林陣列索引——
整數陣列索引根據索引選擇陣列中的元素,布林陣列索引的用法則不同,我們要明確指定選擇哪些元素,索引陣列與原陣列有相同的shape,如下例子。

>>> 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]], dtype=bool)
>>> 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]])

如下例子,使用布林索引生成圖片。

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

如上例子的效果圖如下。
這裡寫圖片描述
布林陣列索引的另一種用法類似於整數陣列索引,如下例子,對於陣列的每一個維來說,使用一個一維的布林陣列進行索引。

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

布林索引陣列的大