先決條件
在閱讀這個(gè)教程之前,你多少需要知道點(diǎn)python。如果你想重新回憶下,請(qǐng)看看Python Tutorial
如果你想要運(yùn)行教程中的示例,你需要在你的電腦上安裝了一些軟件,詳細(xì)內(nèi)容請(qǐng)查看
http://scipy.org/install.html
基礎(chǔ)篇
NumPy的主要對(duì)象是同種元素的多維數(shù)組。這是一個(gè)所有的元素都是一種類型、通過一個(gè)正整數(shù)元組索引的元素表格(通常是元素是數(shù)字)。在NumPy中維度(dimensions)
叫做軸(axes)
,軸的個(gè)數(shù)叫做秩(rank)
。
例如,在3D空間一個(gè)點(diǎn)的坐標(biāo)
[1, 2, 3]
是一個(gè)秩為1的數(shù)組,因?yàn)樗挥幸粋€(gè)軸,且軸長度為3。
例如,
[[ 1., 0., 0.],
[ 0., 1., 2.]]
以上例子中,數(shù)組的秩為2(它有兩個(gè)維度)。第一個(gè)維度長度為2,第二個(gè)維度長度為3。
NumPy的數(shù)組類被稱作ndarray
。通常被稱作數(shù)組(array)
。注意numpy.array
和標(biāo)準(zhǔn)Python庫類array.array
并不相同,后者只處理一維數(shù)組和提供少量功能。更多重要ndarray
對(duì)象屬性有:
ndarray.ndim
數(shù)組軸(axes)的個(gè)數(shù),在python的世界中,軸的個(gè)數(shù)被稱作秩(rank)
ndarray.shape
數(shù)組的維度(dimensions)。這是一個(gè)指示數(shù)組在每個(gè)維度上大小的整數(shù)元組。
例如一個(gè)n排m列的矩陣,它的
shape
屬性將是(n,m)
,這個(gè)元組的長度顯然是秩(rank),即維度(dimensions)或者ndim
屬性
ndarray.size
數(shù)組元素的總個(gè)數(shù),等于shape
屬性中元組元素的乘積。
ndarray.dtype
一個(gè)用來描述數(shù)組中元素類型的對(duì)象,可以通過創(chuàng)造或指定dtype使用標(biāo)準(zhǔn)Python類型。另外NumPy提供它自己的數(shù)據(jù)類型。numpy.int32, numpy.int16, numpy.float64等等。
ndarray.itemsize
數(shù)組中每個(gè)元素的字節(jié)大小。
例如,一個(gè)元素類型為
float64
的數(shù)組itemsize
屬性值為8(=64/8)
又如,一個(gè)元素類型為
complex32
的數(shù)組itemsize
屬性為4(=32/8)。和ndarray.dtype.itemsize
值相同。
ndarray.data
包含實(shí)際數(shù)組元素的緩沖區(qū),通常我們不需要使用這個(gè)屬性,因?yàn)槲覀兛偸峭ㄟ^索引來使用數(shù)組中的元素。
例子
>>> 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'>
創(chuàng)建數(shù)組(array)
有好幾種創(chuàng)建數(shù)組的方法。例如,你可以使用array
函數(shù)從常規(guī)的Python列表和元組創(chuàng)造數(shù)組。所創(chuàng)建的數(shù)組類型由原序列中的元素類型推導(dǎo)而來。
>>> 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')
一個(gè)常見的錯(cuò)誤包括用多個(gè)數(shù)值參數(shù)調(diào)用array
而不是提供一個(gè)由數(shù)值組成的列表作為一個(gè)參數(shù)。
>>> a = array(1,2,3,4) # WRONG
>>> a = array([1,2,3,4]) # RIGHT
array
函數(shù)將 序列內(nèi)含序列(sequences of sequences)
轉(zhuǎn)化成二維的數(shù)組,序列內(nèi)含序列內(nèi)含序列(sequences of sequences of sequences)
轉(zhuǎn)化成三維數(shù)組等等。
>>> b = np.array([(1.5,2,3), (4,5,6)])
>>> b
array([[ 1.5, 2. , 3. ],
[ 4. , 5. , 6. ]])
數(shù)組類型可以在創(chuàng)建時(shí)顯示指定
>>> c = np.array( [ [1,2], [3,4] ], dtype=complex )
>>> c
array([[ 1.+0.j, 2.+0.j],
[ 3.+0.j, 4.+0.j]])
通常,數(shù)組的元素開始都是未知的,但是它的大小已知。因此,NumPy提供了一些使用占位符創(chuàng)建數(shù)組的函數(shù)。這最小化了擴(kuò)展數(shù)組的需要和高昂的運(yùn)算代價(jià)。
函數(shù)zeros
創(chuàng)建一個(gè)全是0的數(shù)組,函數(shù)ones
創(chuàng)建一個(gè)全1的數(shù)組,函數(shù)empty
創(chuàng)建一個(gè)內(nèi)容隨機(jī)并且依賴內(nèi)存狀態(tài)的數(shù)組。默認(rèn)創(chuàng)建的數(shù)組類型(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]])
為了創(chuàng)建一個(gè)數(shù)列,NumPy提供一個(gè)類似arange
的函數(shù)返回?cái)?shù)組而不是列表
>>> 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])
當(dāng)arange
使用浮點(diǎn)數(shù)參數(shù)時(shí),由于浮點(diǎn)數(shù)精度有限,通常無法預(yù)測(cè)獲得的元素個(gè)數(shù)。因此,最好使用函數(shù)linspace
去接收我們想要的元素個(gè)數(shù)來代替指定步長。
補(bǔ)充
>>> numpy.linspace(-1, 0, 5) array([-1. , -0.75, -0.5 , -0.25, 0. ])
參考 array,zeros,zeros_like,ones,ones_like,empty,empty_like,arange,linspace,numpy.random.rand,numpy.random.randn,fromfunction,fromfile
打印數(shù)組
當(dāng)你打印一個(gè)數(shù)組,NumPy以類似嵌套列表的形式顯示它,但是呈以下布局:
- 最后的軸從左到右打印
- 次后的軸從頂向下打印
- 剩下的軸從頂向下打印,每個(gè)切片通過一個(gè)空行與下一個(gè)隔開
一維數(shù)組被打印成行,二維數(shù)組成矩陣,三維數(shù)組成矩陣列表。
>>> 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]]]
查看下面獲得有關(guān)reshape
的更多細(xì)節(jié)。
如果一個(gè)數(shù)組用來打印太大了,NumPy自動(dòng)省略中間部分而只打印角落:
>>> 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]]
禁用NumPy的這種行為并強(qiáng)制打印整個(gè)數(shù)組,你可以設(shè)置set_printoptions
參數(shù)來更改打印選項(xiàng)。
>>> np.set_printoptions(threshold='nan')
基礎(chǔ)運(yùn)算
數(shù)組的算術(shù)運(yùn)算是按元素的。新的數(shù)組被創(chuàng)建并且被結(jié)果填充。
>>> 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中的*
運(yùn)算符指示按元素計(jì)算,矩陣乘法可以使用dot
函數(shù)或創(chuàng)建矩陣對(duì)象實(shí)現(xiàn):
>>> 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]])
有些操作符像+=
和*=
被用來更改已存在數(shù)組而不創(chuàng)建一個(gè)新的數(shù)組。
>>> 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'
當(dāng)運(yùn)算的是不同類型的數(shù)組時(shí),結(jié)果數(shù)組類型和更普遍或更精確相同(這種行為叫做upcasting)。
>>> 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'
許多一元運(yùn)算,如計(jì)算數(shù)組所有元素之和,都用ndarray
類的方法來實(shí)現(xiàn)。
>>> 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
通常,這些運(yùn)算將數(shù)組看作是一維線性列表,忽略原有形狀(shape)。但可通過指定axis
參數(shù)(即數(shù)組的軸)對(duì)指定的軸做相應(yīng)的運(yùn)算:
>>> 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]) #如果axis是1,就計(jì)算第二軸的值,就是行相加,結(jié)果是array([ 6, 22, 38])
>>>
>>> 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]])
通用函數(shù)
NumPy提供常見的數(shù)學(xué)函數(shù)如sin,cos和exp。在NumPy中,這些叫作“通用函數(shù)(universal functions)”(ufunc
)。在NumPy里這些函數(shù)按數(shù)組的元素運(yùn)算,產(chǎn)生一個(gè)數(shù)組作為輸出。
>>> 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.])
參考all,any,apply_along_axis,argmax,argmin,argsort,average,bincount,ceil,clip,conj,corrcoef,cov,cross,cumprod,cumsum,diff,dot,floor,inner,inv,lexsort,max,maximum,mean,median,min,minimum,nonzero,outer,prod,re,round,sort,std,sum,trace,transpose,var,vdot,vectorize,where
索引,切片和迭代
一維數(shù)組可以被索引、切片和迭代,就像列表(lists)和其它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
多維數(shù)組可以每個(gè)軸有一個(gè)索引。這些索引由一個(gè)逗號(hào)分割的元組給出:
>>> 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]])
當(dāng)少于軸數(shù)的索引被提供時(shí),缺失的索引被認(rèn)為是整個(gè)切片:
>>> b[-1] # the last row. Equivalent to b[-1,:]
array([40, 41, 42, 43])
b[i]
中括號(hào)中的表達(dá)式被當(dāng)作i
和一系列:
,來代表剩下的軸。NumPy也允許你像b[i,...]
來寫。
點(diǎn)(…
)代表許多產(chǎn)生一個(gè)完整的索引元組必要的分號(hào)。如果x
是秩為5的數(shù)組(即它有5個(gè)軸),那么:
-
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)多維數(shù)組是就第一個(gè)軸而言的:
>>> 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]
但是,如果一個(gè)人想對(duì)每個(gè)數(shù)組中元素進(jìn)行運(yùn)算,我們可以使用flat
屬性,該屬性是數(shù)組所有元素的一個(gè)迭代器:
>>> 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
變形操作
更改數(shù)組的形狀
一個(gè)數(shù)組的形狀由它每個(gè)軸上的元素個(gè)數(shù)給出:
>>> 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)
一個(gè)數(shù)組的形狀可以被多種命令修改。注意下面三種命令都返回一個(gè)被修改的數(shù)組,并沒有改變?cè)瓉淼臄?shù)組:
>>> 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 轉(zhuǎn)置
array([[ 2., 4., 8.],
[ 8., 5., 9.],
[ 0., 1., 3.],
[ 6., 1., 6.]])
>>> a.T.shape
(4, 3)
>>> a.shape
(3, 4)
由ravel()展平的數(shù)組元素的順序通常是“C風(fēng)格”的,就是說,最右邊的索引變化得最快,所以元素a[0,0]之后是a[0,1]。如果數(shù)組被改變形狀(reshape)成其它形狀,數(shù)組仍然是“C風(fēng)格”的。NumPy通常創(chuàng)建一個(gè)以這個(gè)順序保存數(shù)據(jù)的數(shù)組,所以ravel()將總是不需要復(fù)制它的參數(shù)。但是如果數(shù)組是通過切片其它數(shù)組或有不同尋常的選項(xiàng)時(shí),它可能需要被復(fù)制。函數(shù)reshape()和ravel()還可以被同過一些可選參數(shù)構(gòu)建成FORTRAN風(fēng)格的數(shù)組,即最左邊的索引變化最快。
reshape
函數(shù)改變參數(shù)形狀并返回它,而ndarray.resize
函數(shù)改變數(shù)組自身。
>>> 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.]])
如果在改變形狀操作中一個(gè)維度被給做-1,其維度將計(jì)算計(jì)算:
>>> a.reshape(3,-1)
array([[ 2., 8., 0., 6.],
[ 4., 5., 1., 1.],
[ 8., 9., 3., 6.]])
組合(stack)不同的數(shù)組
幾個(gè)數(shù)組可以沿不同的軸組合在一起:
>>> 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.]])
函數(shù)column_stack以列將一維數(shù)組合成二維數(shù)組,它等同于vstack僅對(duì)一維數(shù)組。
>>> 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.]])
對(duì)那些維度比二維更高的數(shù)組,hstack沿著第二個(gè)軸組合,vstack沿著第一個(gè)軸組合,concatenate允許可選參數(shù)給出組合時(shí)沿著的軸。
Note
在復(fù)雜情況下,r_和c_對(duì)創(chuàng)建沿著一個(gè)方向組合的數(shù)很有用,它們?cè)试S范圍符號(hào)(“:”):
>>> np.r_[1:4,0,4]
array([1, 2, 3, 0, 4])
當(dāng)使用數(shù)組作為參數(shù)時(shí),r_和c_的默認(rèn)行為和vstack和hstack很像,但是允許可選的參數(shù)給出組合所沿著的軸的序號(hào)。
將一個(gè)數(shù)組分割(split)成幾個(gè)小數(shù)組
使用hsplit你能將數(shù)組沿著它的水平軸分割,或者指定返回相同形狀數(shù)組的個(gè)數(shù),或者指定在哪些列后發(fā)生分割:
>>> 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允許指定沿哪個(gè)軸分割。
復(fù)制和視圖
當(dāng)運(yùn)算和處理數(shù)組時(shí),它們的數(shù)據(jù)有時(shí)被拷貝到新的數(shù)組有時(shí)不是。這通常是新手困惑的地方。這有三種情況:
完全不拷貝
簡單的賦值不拷貝數(shù)組對(duì)象或它們的數(shù)據(jù)。
>>> 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傳遞不定對(duì)象時(shí)只傳遞對(duì)象引用,所以函數(shù)調(diào)用不拷貝數(shù)組。
>>> def f(x):
... print(id(x))
...
>>> id(a) # id is a unique identifier of an object
148293216
>>> f(a)
148293216
視圖(View)或淺復(fù)制(Shallow Copy)
不同的數(shù)組對(duì)象可以共享同一數(shù)據(jù)。視圖(view
)方法創(chuàng)造一個(gè)新的數(shù)組對(duì)象指向同一數(shù)據(jù)。
>>> 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]])
切片數(shù)組返回它的一個(gè)視圖:
>>> 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]])
深復(fù)制(Deep Copy)
復(fù)制(copy
)方法完全復(fù)制數(shù)組和它的數(shù)據(jù)。
>>> 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]])
函數(shù)和方法總覽
這是個(gè)NumPy函數(shù)和方法分類排列目錄。 查看Routines完整列表。
Array Creation
arange,array,copy,empty,empty_like,eye,fromfile,fromfunction,identity,linspace,logspace,mgrid,ogrid,ones,ones_like,r,zeros,zeros_like
Conversions
ndarray.astype,atleast_1d,atleast_2d,atleast_3d,mat
Manipulations
array_split,column_stack,concatenate,diagonal,dsplit,dstack,hsplit,hstack,ndarray.item,newaxis,ravel,repeat,reshape,resize,squeeze,swapaxes,take,transpose,vsplit,vstack
Questions
all,any,nonzero,where
Ordering
argmax,argmin,argsort,max,min,ptp,searchsorted,sort
Operations
choose,compress,cumprod,cumsum,inner,ndarray.fill,imag,prod,put,putmask,real,sum
Basic Statistics
cov,mean,std,var
Basic Linear Algebra
cross,dot,outer,linalg.svd,vdot
進(jìn)階
廣播法則(rule)
廣播法則能使通用函數(shù)有意義地處理不具有相同形狀的輸入。
廣播第一法則是,如果所有的輸入數(shù)組維度不都相同,一個(gè)“1”將被重復(fù)地添加在維度較小的數(shù)組上直至所有的數(shù)組擁有一樣的維度。
廣播第二法則確定長度為1的數(shù)組沿著特殊的方向表現(xiàn)地好像它有沿著那個(gè)方向最大形狀的大小。對(duì)數(shù)組來說,沿著那個(gè)維度的數(shù)組元素的值理應(yīng)相同。
應(yīng)用廣播法則之后,所有數(shù)組的大小必須匹配。更多細(xì)節(jié)可以從這個(gè)文檔找到。
花哨的索引和索引技巧
NumPy比普通Python序列提供更多的索引功能。除了索引整數(shù)和切片,正如我們之前看到的,數(shù)組可以被整數(shù)數(shù)組和布爾數(shù)組索引。
通過數(shù)組索引
>>> 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]])
當(dāng)被索引數(shù)組a
是多維的時(shí),每一個(gè)唯一的索引數(shù)列指向a
的第一維。以下示例通過將圖片標(biāo)簽用調(diào)色版轉(zhuǎn)換成色彩圖像展示了這種行為。
>>> 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]]])
我們也可以給出不不止一維的索引,每一維的索引數(shù)組必須有相同的形狀。
>>> 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]]])
自然,我們可以把i
和j
放到序列中(比如說列表)然后通過list索引。
>>> l = [i,j]
>>> a[l] # equivalent to a[i,j]
array([[ 2, 5],
[ 7, 11]])
然而,我們不能把i
和j
放在一個(gè)數(shù)組中,因?yàn)檫@個(gè)數(shù)組將被解釋成索引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]])
另一個(gè)常用的數(shù)組索引用法是搜索時(shí)間序列最大值。
>>> 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
你也可以使用數(shù)組索引作為目標(biāo)來賦值:
>>> a = np.arange(5)
>>> a
array([0, 1, 2, 3, 4])
>>> a[[1,3,4]] = 0
>>> a
array([0, 0, 2, 0, 0])
然而,當(dāng)一個(gè)索引列表包含重復(fù)時(shí),賦值被多次完成,保留最后的值:
>>> a = np.arange(5)
>>> a[[0,0,2]]=[1,2,3]
>>> a
array([2, 1, 3, 3, 4])
這足夠合理,但是小心如果你想用Python的+=
結(jié)構(gòu),可能結(jié)果并非你所期望:
>>> a = np.arange(5)
>>> a[[0,0,2]]+=1
>>> a
array([1, 1, 3, 3, 4])
即使0在索引列表中出現(xiàn)兩次,索引為0的元素僅僅增加一次。這是因?yàn)镻ython要求a+=1和a=a+1等同。
通過布爾數(shù)組索引
當(dāng)我們使用整數(shù)數(shù)組索引數(shù)組時(shí),我們提供一個(gè)索引列表去選擇。通過布爾數(shù)組索引的方法是不同的我們顯式地選擇數(shù)組中我們想要和不想要的元素。
我們能想到的使用布爾數(shù)組的索引最自然方式就是使用和原數(shù)組一樣形狀的布爾數(shù)組。
>>> 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])
這個(gè)屬性在賦值時(shí)非常有用:
>>> 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()
第二種通過布爾來索引的方法更近似于整數(shù)索引;對(duì)數(shù)組的每個(gè)維度我們給一個(gè)一維布爾數(shù)組來選擇我們想要的切片:
>>> 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])
注意一維數(shù)組的長度必須和你想要切片的維度或軸的長度一致,在之前的例子中,b1
是一個(gè)秩為1長度為3的數(shù)組(a
的行數(shù)),b2
(長度為4)與a
的第二秩(列)相一致。
ix_()函數(shù)
ix_函數(shù)可以為了獲得的結(jié)果而用來結(jié)合不同向量。例如,如果你想要用所有向量a、b和c元素組成的三元組來計(jì)算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
你也可以實(shí)行如下簡化:
>>> 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]]])
這個(gè)reduce與ufunc.reduce(比如說add.reduce)相比的優(yōu)勢(shì)在于它利用了廣播法則,避免了創(chuàng)建一個(gè)輸出大小乘以向量個(gè)數(shù)的參數(shù)數(shù)組。
用字符串索引
線性代數(shù)
繼續(xù)前進(jìn),基本線性代數(shù)包含在這里。
簡單數(shù)組計(jì)算
參考numpy文件夾中的linalg.py獲得更多信息
>>> 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]])
>>> np.dot (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]`` .
技巧和建議
在這里我們給出一些短而且有用的建議
“自動(dòng)”變形
要改變一個(gè)數(shù)組的維度,你可以漏掉一個(gè)可以被自動(dòng)推斷出來的大小
>>> 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]]])
向量疊加
怎樣通過相同大小的向量構(gòu)建一個(gè)二維數(shù)組?MATLAB里面很容易:如果x
和y
是兩個(gè)相同長度的向量,你只要m=[x;y]
。在NumPy中可以通過函數(shù)column_stack
, dstack
, hstack
和 vstack
,取決于在哪個(gè)維度疊加,例如:
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])
這些方法的邏輯用在多于兩個(gè)維度的地方會(huì)很奇怪。
直方圖(histogram)
NumPy中·histogram·函數(shù)應(yīng)用到一個(gè)數(shù)組返回一對(duì)向量:直方圖數(shù)組和箱式向量。注意:matplotlib
也有一個(gè)用來建立直方圖的函數(shù)(叫作hist
,正如matlab中一樣)與NumPy中的不同。主要的差別是pylab.hist
自動(dòng)繪制直方圖,而numpy.histogram
僅僅產(chǎn)生數(shù)據(jù)
>>> 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, normed=1) # matplotlib version (plot)
>>> plt.show()