<!DOCTYPE html>
numpy提供了兩種基本的對象,ndarray,ufunc
html
Numpy中全部的函數都是圍繞ndarray對象進行的
python
import numpy as np
a=np.array([1,2,3,4]) #列表作參數
b=np.array((5,6,7,8)) #元祖作參數
c=np.array([[1,2,3,4],[5,6,7,8],[7,8,9,10]])
想知道數組的形狀能夠用 shape屬性(不是函數)得到,他是一個描述數組各軸的長度的元祖(tuple) git
a.shape #輸出(4,)一個元素,一維數組
b.shape #輸出(4,)
c.shape #輸出(3,4)兩個元素,二維數組 0軸3,一軸4
能夠經過修改數組的shape屬性,在保持數組元素個數不變的狀況下,改變數組每一個軸的長度,只是改變軸長,數組元素在內存中的位置不變 c.shape=(4,3) 數組將改變軸長 當設置某個軸的元素個數爲-1時,將自動計算此軸的長度。
c.shape(2,-1) c的shape屬性將變爲(2,6)
使用reshape()方法,能夠建立指定的形狀的新數組,而原數組形狀不變, d=a.reshape((2,2)) #也能夠用a.reshape(2,2) d#輸出[[1,2],[3,4]]
數組a和d共享數據存儲空間,所以修改任意元素,另外一個數組也會被修改
2. 元素類型
數組的元素類型能夠經過dtype屬性獲取,類型有int32,float64,complex128,當須要指定dtype參數時,可使用字符串,全部的元素類型關係都存儲在typeDict字典中。獲取與float64類型對應的全部鍵值
列表推導 github
[key for key,value in np.typeDict.items() if value is np.float64]
set(np.typeDict.values())獲取全部typeDict值並去重,這種方式獲取的屬性與dtype是不一樣的對象,經過dtype對象的type屬性能夠找到與其對應的數值
c.dtype.type #輸出numpy.int32
經過numpy也能夠建立數值對象,但運算比python數值對象運算慢。
使用astype()方法能夠對數組的元素類型進行轉換, web
t1=np.array([1,2,3,4],dtype=np.float)
t2=np.array([1,2,3,4],dtype=np.complex)
t3=t1.astype(np.init32)
t4=t2.astype(np.complex64)
自動生成數組
前面例子都是先建立一個序列對象,而後經過array轉化爲數組,顯然效率不高。所以Numpy提供了許多專門的建立數組的函數 canvas
logspace()爲等比數列,下面產生從10^0 到10^二、有5個元素的等比數列,注意起始值0表示10^0,而終值2表示10^2:
np.logspace(0,2,5)
array([ 1. , 3.16227766, 10. , 31.6227766 , 100. ])
基數能夠經過base參數指定,其默認值爲10,下面將base參數設置爲2,並設置endpoint參數爲False,建立一個比例爲2^1/12的等比數組。
np.logspace(0,1,12,base=2,endpoint=False) array([ 1. , 1.05946309, 1.12246205, 1.18920712, 1.25992105, 1.33483985, 1.41421356, 1.49830708, 1.58740105, 1.68179283, 1.78179744, 1.88774863]) 數組
empyt(),zeros(),ones()能夠建立指定形狀和類型的數組,empyt初始化元素爲0,zeros初始化元素爲0,ones初始化元素爲1
np.empty((2,3),np.int) array([[0, 0, 0], [0, 0, 0]]) np.ones(3,np.int) array([1, 1, 1]) np.zeros(2,np.int) array([0, 0])ruby
fromfunction,先定義一個從下標計算數值的函數,而後用fromfunction()經過此函數建立數組,下標從0,1,2,3,4...依次計算,下標從第二個參數規定的軸開始計算
def func(i): return i%4+1 np.fromfunction(func,(10,)) array([ 1., 2., 3., 4., 1., 2., 3., 4., 1., 2.]) markdown
def func2(x,y): return (x+1)*(y+1)
np.fromfunction(func2,(2,3)),傳進去的參數依次爲[(0,0),(0,1),(0,2)],[(1,0),(1,1),(1,2)]
array([[ 1., 2., 3.], [ 2., 4., 6.]])
存取元素有兩種,一種和列表相同的方式,另外一種使用列表或者數組下標的方式,
可使用和列表相同的方式對數組元素進行存取 獲取的元素和原數組共享內存
a=np.arange(10) a[5]:用整數做爲下標能夠獲取數組中的某個元素
a[3:5] 用切片做爲下標獲取數組的一部分,包括a[3]但不包括a[5]包頭不包尾
a[:5] 切片中省略開始下標,表示從a[0]開始
a[:-1] 下標可使用負數,表示從數組最後往前數
a[1:-1:2] 切片中的第三個參數表示步長,2表示隔一個去一個元素
a[::-1] 省略切片的開始下標和結束下標,步長爲-1,整個數組顛倒過來
a[5:1:-2] 步長爲負數是,開始下標必須大於結束下標
下標能夠用來修改元素
a[2:4]=100,101
除了使用切片,還提供了整數列表、整數數組和布爾數組等幾種高級下標存取方法,在numpy10.1之後,布爾列表和布爾數組取得結果相同不共享內存
多維數組
多維數組的存取和一維數組相似,由於多維數組有多個軸,因此它的下標須要用多個值來表示。Numpy採用元祖做爲數組的下標,元祖中的每隔元素和數組的每一個軸對應。
a=np.arange(0,60,10).reshape(-1,1)+np.arange(0,6)
a[0,3:5] #3,4 a[4:,4:] #44,45,54,55 a[:,2] #2,12,22,32,42,52 a{2::2,::2] #20,22,24,40,42,44 下標元祖與原數組共享數據
在多維數組的下標元祖中,也可使用整數元祖或列表、整數數組和布爾數組,當下標中使用這些對象時,得到的數據是元數據的副本,更改不會改變元數據
a[(0,1,2,3),(1,2,3,4)] #獲取(0,1),(1,2),(2,3),(3,4)
a[3:,[0,2,5]] #獲取(3,0)(3,2)(3,5)(4,0)(4,2)(4,5)(5,0)(5,2)(5,5)
mask=np.array([1,0,1,0,0,1],dtype=np.bool) a[mask,2] #獲取(0,2),(2,2)(5,2)
結構數組
假設咱們須要定義一個結構數組,他的每一個元素都有name,age和weight字段。在numpy中能夠這樣定義 persiontype=np.dtype({'names':['name','age','weight'],'formats':['S30','i','f']},align=True)
a=np.array([('wang',32,75.5),('zhang',24,65.2)],dtype=persiontype)
array([(b'wang', 32, 75.5 ), (b'zhang', 24, 65.19999695)], dtype={'names':['name','age','weight'], 'formats':['S30','<i4','<f4'], 'offsets':[0,32,36], 'itemsize':40, 'aligned':True})
dtype({'names':['name','age','weight'], 'formats':['S30','<i4','<f4'], 'offsets':[0,32,36], 'itemsize':40}, align=True)
a[0] (b'wang', 32, 75.5)
a[0]['name'] b'wang' a[0]是結構元素,他和數組a共享內存數據
咱們不但能夠得到結構元素的某個字段,並且能夠直接得到結構數組的字段,返回的是原始數組的視圖,所以能夠經過改變b[0]來改變a[0]['age'] b=a['name']
b[0] b'wang' b[1] b'zhang'
經過a.tostring()或a.tofile()方法,能夠將數組a以二進制的方式轉換城字符串或寫入文件
結構類型中能夠包含其餘結構類型
np.dtype(['f1',[('f22',np.int16)])]) 當某個字段類型爲數組是,用元祖的第三個元素表示其形狀
np.dtype([('f0','i4'),('f1','f8',(2,3))]) 字典的鍵爲結構的字段名,值爲字段的類型描述,可是因爲字典的鍵是沒有順序的,所以字段的順序須要在類型描述中給出。類型描述是一個元祖,它的第二個值給出的字段以字節爲單位的偏移量,偏移量用於避開第一個字段的長度
np.dtype({'sunname':('S25',0),'age':(np.uint8,25)})
內存結構
好東西,重要屬性,strides步長,指內存裏的數據相隔的字節數
a=np.array([[1,2,3,4],[5,6,7,8]])
a.strides (16, 4)#首先這個元祖裏的元素的下標對應的是多維數組中的維數,此結果表示的是第0軸和第1軸,這是一個2維數組,由於數組內存連續,元素類型爲int32,因此1與2之間間隔四個字節,1,2,3,4這四個元素共用16字節,因此1與5相聚16字節
元素在數據存儲區中的排列格式有兩種:C語言格式和Fortran語言格式。在C語言中第0軸中元素相隔最遠,第1軸相隔最近,而F中相反 C的存儲方式是Z型,F是倒着的N型
a.flags CCONTIGUOUS : True FCONTIGUOUS : False OWNDATA : True WRITEABLE : True ALIGNED : True UPDATEIFCOPY : False
a.T.flags CCONTIGUOUS : False FCONTIGUOUS : True OWNDATA : False WRITEABLE : True ALIGNED : True UPDATEIFCOPY : False
當時用view()方法從同一塊數據區建立不一樣的dtype的數組對象,也就是使用不一樣的數值類型查看同一段內存中的二進制數據
g=e.view(np.uint8) g array([0, 0, 0, 0, 1, 0, 0, 0, 2, 0, 0, 0, 3, 0, 0, 0, 4, 0, 0, 0, 5, 0, 0, 0], dtype=uint8) e array([0, 1, 2, 3, 4, 5]) h=e.view(np.uint32)h array([0, 1, 2, 3, 4, 5], dtype=uint32)
有趣實驗
from numpy.lib.stridetricks import asstrided i=np.arange(6) j=as_strided(i,shape=(4,3),strides=(4,4)) j array([[0, 1, 2], [1, 2, 3], [2, 3, 4], [3, 4, 5]]) i array([0, 1, 2, 3, 4, 5])
strides規定了如何取數據,shape規定了數組形狀,好比j第(0,0)位取0,那麼根據strides,第0軸和第一軸間隔字節數按4來查找,第(0,1)位就應該是1,由於1與0相隔4個字節,這裏的數據是部分重複的,修改一個其餘的也被修改。
ufunc (universal function(通用函數)),許多ufunc都是用C語言實現的,所以它們計算速度很是快。
np.sin() 比 math.sin()快10倍
經過下標運算獲取的數組元素類型位NumPy中定義的類型,將其轉換爲python的標準類型還須要花費額外的時間。爲了解決這個問題,數組提供了item()方法,它用來獲取數組中的單個元素,而且直接返回標準的 python數值類型
1. 四則運算
1. 加法(使用+號或者使用np.add()方法)
>>> np.add(a,b)
array([[ 0., 3., 6.],
[ 9., 12., 15.]])
>>> a+b
array([[ 0., 3., 6.],
[ 9., 12., 15.]])
>>> b
array([[ 0., 2., 4.],
[ 6., 8., 10.]])
>>> a
array([[0, 1, 2],
[3, 4, 5]])
使用add方法,能夠指定第三個參數out,則不產生新的數組,而直接將結果保存進指定的數組
np.add(a,b,b) 等效於 a=a+b
array([[ 0., 3., 6.],
[ 9., 12., 15.]])
2. 其餘運算
>>> x1=np.array([1,2,3,4,5])
>>> x2=np.array([2,3,4,5,6])
>>> y=x1*x2(y=multiply(x1,x2))
>>> y
array([ 2, 6, 12, 20, 30])
>>> y=x1-x2 (y=subtract(x1,x2))
>>> y
array([-1, -1, -1, -1, -1])
>>> y=x1/x2 (y=divide(x1,x2))
>>> y
array([ 0.5 , 0.66666667, 0.75 , 0.8 , 0.83333333])
>>> y=x1//x2 (y=floor_divide(x1,x2),老是對返回值取整)
>>> y
array([0, 0, 0, 0, 0], dtype=int32)
>>> y=-x1 (y=negative(x))
>>> y
array([-1, -2, -3, -4, -5])
>>> y=x1**x2 (power(x1,x2))
>>> y
array([ 1, 8, 81, 1024, 15625], dtype=int32)
>>> y=x1%x2 (mod(x1,x2),remainder(x1,x2))
>>> y
array([1, 2, 3, 4, 5], dtype=int3
數組運算支持操做符,簡化了編寫,當算式複雜時,避免中間值
a*b+c算式寫成
x=a*b
x+=c
np.array([1,2,3])<np.array([3,2,1])
array([ True, False, False], dtype=bool)
y=x1==x2 y=equal(x1,x2)
y=x1!=x2 y=not_equal(x1,x2)
y=x1<x2 y=less(x1,x2)
y=x1<=x2 y=less_equal(x1,x2)
y=x1>x2 y=geater(x1,x2)
y=x1>=x2 y=greater_equal(x1,x2)
布爾運算在ufunc函數中,函數名以logical開頭,
np.logicaland np.logicalnot np.logicalor np.logicalxor
例子
a=np.arange(5) b=np.arange(4,-1,-1) np.logicalor(a==b,a>b)
數組的any()和all()方法
只有數組中有一個元素爲True,any()方法就返回True
只有全部元素的爲True,all()才返回True
以bitwise開頭的爲位運算函數,包括bitwiseand、bitwise_not、bitwiseor、bitwisexor,也可使用&,~,|,^操做符進行運算,位運算結果與布爾運算結果相同
(a==b)|(a>b) 由於位運算符比比較運算符優先級高,因此須要加括號提高優先級
自定義ufun函數
能夠用frompyfunc()函數將計算單個元素的函數轉換成數組ufunc函數,這樣就能夠用所產生的ufunc函數對數組進行計算
舉例,計算三角波,三個階段,上坡,下坡,平坦
def trianglewave(x,c,c0,hc): x=x-int(x) #三角波的週期爲1
if x>=c: r=0.0
elif x<c0: x=x/c0hc
else: r=(c-x)/(c-c0)hc
return r
先使用列表推導計算出一個列表,而後用array()將列表轉換爲數組。每次使用列表推導調用 函數,多維數組應用很麻煩 x=np.linspace(0,2,1000) y1=np.array([trianglewave(t,0.6,0.4,1.0) for t in x])
經過frompyfunc()能夠將計算單個值的函數轉換位能對數組的每一個元素進行計算的ufunc函數。frompyfunc()的調用能格式
frompyfunc(func,func須要輸入參數個數,func返回參數個數) triangleufunc1=np.frompyfunc(trianglewave,4,1)
y2=triangle_ufunc1(x,0.6,0.4,1.0)
triangleufunc1()返回的數組的元素類型爲object,所以還須要調用數組astype()方法,以將其轉換爲雙精度浮點數組: y2.dtype #dtype('O') y2.astype(np.float).dtype #dtype('float64')
使用vectorize()也能夠實現和frompyfunc()相似的功能,但它能夠經過otypes參數指定返回數組的元素類型。otypes參數能夠是一個表示元素類型的字符串,也能夠是一個類型列表,使用列表能夠描述多個返回數組的元素類型
triangleufunc2 = np.vectorize(trianglewave,otypes=[np.float])
y3=triangleufunc2(x,0.6,0.4,1.0)
驗證咱們的結果
np.all(y1==y2) # True
np.all(y2==y3) # True
廣播
當時用ufunc函數對兩個數組進行計算時,ufunc函數會對兩個數組的對應的元素進行計算,所以要求兩個數組形狀相同,,若是不一樣,會調用廣播來處理
a=np.arange(0,60,10).reshape(-1,1) b=np.arange(0,5) c=a+b
x,y=np.ogrid[-2:2:20j,-2:2:20j] z=xnp.exp(-x2-y*2) 在x前加負號不知道爲啥,exp計算各元素指數ex; z array([[-0.00067093, -0.00148987, -0.00302777, -0.00563122, -0.00958484, -0.01493034, -0.02128422, -0.02776827, -0.03315453, -0.03622763, -0.03622763, -0.03315453, -0.02776827, -0.02128422, -0.01493034, -0.00958484, -0.00563122, -0.00302777, -0.00148987, -0.00067093], ... [ 0.00067093, 0.00148987, 0.00302777, 0.00563122, 0.00958484, 0.01493034, 0.02128422, 0.02776827, 0.03315453, 0.03622763, 0.03622763, 0.03315453, 0.02776827, 0.02128422, 0.01493034, 0.00958484, 0.00563122, 0.00302777, 0.00148987, 0.00067093]])
z.shape (20, 20) z.dtype dtype('float64') 爲了利用廣播功能,常常須要調整數組的形狀,所以數組支持特殊的下標對象None,它表示在None對應的位置建立一個長度爲1的新軸如:a[None,:]和a.reshape(1,-1)等效,而a[:None]和a.reshape(-1,1)等效
還可使用ix()函數將兩個一維數組轉換成可廣播的二維數組
x=np.array([0,1,4,10]) >>> y=np.array([2,3,8]) >>> gy,gx=np.ix(y,x) >>> gy array([[2], [3], [8]]) >>> gx array([[ 0, 1, 4, 10]]) >>> gz=gy+gx >>> gz array([[ 2, 3, 6, 12], [ 3, 4, 7, 13], [ 8, 9, 12, 18]]) 經過ix()函數將數組x和y轉換成能進行廣播運算的二維數組。數組y對應結果0軸,x對應1軸。ix()的參數能夠時N個一維數組,將這些數組轉換成N維空間中可廣播的N維數組
5. ufunc方法
ufunc對象自己還有一些方法函數,這些方法只對兩個輸入,一個輸出的ufunc函數有效,其餘的ufunc對象調用這些方法會拋出異常 reduce()方法它沿着axis參數指定的軸對數組進行操做,至關於將運算符沿axis軸插入到全部元素中間
r1=np.add.reduce([1,2,3]) #1+2+3 6
r2=np.add.reduce([[1,2,3],[4,5,6]],axis=1) #(1+2+3),(4+5+6)
[6,15]
accumulate()方法和reduce()相似,只是它返回的數組和輸入數組的形狀相同,保存因此的中間計算結果
a1=np.add.accumulate([1,2,3]) #a1 [1,3,6]
a2=np.add.accumulate([[1,2,3],[4,5,6]],axis=1)# a2 [[1,3,6],[4,9,15]]
reduceat()方法計算多組reduce()結果,經過indices參數指定一系列的起始和終止位置
a=np.array([1,2,3,4])
result=np.add.reduceat(a,indices=[0,1,0,2,0,3,0])
result # array([1,2,3,3,6,4,10])
對於indices參數中的每一個元素都會計算出一個值,由於最紅的計算結果和indices參數的長度相同。結果數組result中除最後一個元素以外。
if indices[i]<indices[i+1]
result[i]=<op>.reduce(a[indices[i]:indices[i+1]])
else:
result[i]=a[indices[i]]
而最後一個元素以下計算
1:a[0] ->1
2:a[1] ->2
3:a[0]+a[1] -> 1+2
3:a[2] ->3
6:a[0]+a[1]+a[2] -> 1+2+3=6
4:a[3] ->4
10: a[0] + a[1] +a[2]+a[3] -> 1+2+3+4=10
ufunc函數對象的outer()方法 np.multiply.outer([1,2,3,4,5],[2,3,4])
至關於 a.shape+=(1,)*b.ndim ,
2 3 4 1 2 3 4 2 4 6 8 3 6 9 12 4 8 12 16 5 10 15 20
首先,多維數組的下標應該是一個長度和數組的維度相同的元祖。若是下標元組的長度比數組的維數大,就會出錯。若是小,就會在下標元組後面補":",使它的長度與數組維數相同
若是下標對象不是元組,則numpy會首先把他轉換爲元組。 通過各類轉換和添加「:」以後獲得一個標準的下標元組。它的各個元素有以下幾種類型:切片、整數、整數數組和布爾數組。若是元素不是這些類型,如列表或元組,就將其轉換成整數數組。若是下標元組的全部元素都是切片和整數,那麼他是原數組的一個視圖,共享內存。
2. 整數數組做爲下標
下標元組中元素的切片和整數數組構成的狀況。假設整數數組有Nt個,而切片有Ns個。Nt+Ns爲數組的維數D 首先,這Nt個整數數組必須知足廣播條件,假設它們進行廣播以後的維數爲M,形狀爲(d0,d1,...,dM-1)
若是Ns爲0,即沒有切片元素時,則下標所獲得的結果數組result的形狀和整數數組廣播以後的形狀相同。它的每一個元素值按照下面的公式得到: result[i0,i1,...,im-1]=X[ind0[i0,i1,...,iM-1]...,indNt-1[i0,i1,...,im-1]]
其中,ind0到indNt-1爲進行廣播以後的整數數組
當存在切片下標時,狀況就變得更加複雜。下標元組中的整數數組之間沒有下標,即整數數組只有一個或連續多個整數數組。這是結果數組的shape屬性爲,姜原始數組的shape屬性中的整數數組所佔據的部分替換爲它們廣播以後的shape屬性。
當下標元組中的整數數組不連續時,結果數組的shape屬性爲整數數組廣播以後的形狀後面添加上切片元素所對應的形狀
3. 一個複雜的例子
4. 布爾數組作下標
當時用布爾數組直接做爲下標對象或者元組下標對象中有布爾數組時,都至關於nonzero()將布爾數組轉換成一組整數數組,而後使用整數數組進行下標運算
b1=np.array([True,False,True,False])
np.nonzero(b1)
(array([0, 2], dtype=int64),)
a[np.nonzero(b2)] array([[ 0, 1, 2, 3, 4], [10, 11, 12, 13, 14], [20, 21, 22, 23, 24]])