Numpy快速處理數據
numpy提供了兩種基本的對象,ndarray,ufunc
ndarray對象
Numpy中所有的函數都是圍繞ndarray對象進行的
1. 創建
首先需要創建數組,通過給array()函數傳遞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)
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類型對應的所有鍵值
列表推導
[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()方法可以對數組的元素類型進行轉換,
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提供了許多專門的創建數組的函數- arange()函數類似於內置函數range(),需要指定,開始值、終值和步長,生成結果不包括終值。
np.arange(0,2,0.1)
array([ 0. , 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9]) - linspace()為等差數列,可以通過指定endpoint參數指定是否包含終值,默認值為True,包含終值。
np.linspace(0,1,10) 輸出array([ 0. , 0.11111111, 0.22222222, 0.33333333, 0.44444444, 0.55555556, 0.66666667, 0.77777778, 0.88888889, 1. ]) np.linspace(0,1,10,endpoint=False) 輸出array([ 0. , 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9]) -
logspace()為等比數列,下面產生從10^0 到10^2、有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]) - full()函數將數組元素初始化為指定值 np.full(3,234) array([234, 234, 234])
- fromstring()方法可以將字符串轉成整數數組
np.fromstring('abcdefgh',dtype=np.int8) array([ 97, 98, 99, 100, 101, 102, 103, 104], dtype=int8) -
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.])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.]])
- arange()函數類似於內置函數range(),需要指定,開始值、終值和步長,生成結果不包括終值。
-
存取元素有兩種,一種和列表相同的方式,另一種使用列表或者數組下標的方式,
-
可以使用和列表相同的方式對數組元素進行存取 獲取的元素和原數組共享內存
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以后,布爾列表和布爾數組取得結果相同不共享內存
- 當使用整數列表對數組元素進行存取時,,將使用列表中的每個元素作為下標。不共享內存 x=np.arange(10,1,-1) array([10, 9, 8, 7, 6, 5, 4, 3, 2]) x[[3,3,1,8]] 結果取出下標為3318的四個元素 [7,7,9,2] x[[3,3,-3,8]] 結果取出下標為33-38的四個元素 [7,7,4,2]
整數序列下標也可以用來修改元素的值
x[[3,5,1]]=-1,-2,-3 - 當使用整數數組作為數組下標時,將得到一個形狀和下標數組相同的新數組,新數組的每隔元素都是用下標中對應的值作為下標從原數組獲得的值,當數組下標為一維數組時,結果和列表作為下標的結果相同
x=np.arange(10,1,-1) x[np.array([3,3,1,8]) [7,7,9,2] x[np.array([[3,3,1,8],[3,3,-3,8]])] array([[7,7,9,2],[7,7,4,2]])
可以這樣理解:下將下標數組展平為一維數組,並作為下標獲得一個新的一維數組,然后將其形狀修改為下標數組的形狀:
x[[3,3,1,8,3,3,-3,8]].reshape(2,4) - 當時用布爾數組,布爾數組得長度必須和數組得長度相同
x=np.arange(5,0,-1) x array([5,4,3,2,1]) x[np.array([True,False,True,False,False])] array([5,3])
x=np.random.randint(0,10,6)#產生一個長度為6,元素值為0到9的隨機數數組 array([6, 2, 5, 8, 2, 6]) x[x>5] array([6, 8, 6])
- 當使用整數列表對數組元素進行存取時,,將使用列表中的每個元素作為下標。不共享內存 x=np.arange(10,1,-1) array([10, 9, 8, 7, 6, 5, 4, 3, 2]) x[[3,3,1,8]] 結果取出下標為3318的四個元素 [7,7,9,2] x[[3,3,-3,8]] 結果取出下標為33-38的四個元素 [7,7,4,2]
-
-
多維數組
多維數組的存取和一維數組類似,因為多維數組有多個軸,所以它的下標需要用多個值來表示。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型- 當下標使用整數和切片時,所取得數據時等間分布的,只需要修改數據結構中的,dim count(維度),dimensions(維度上的元素個數),stride(個維度上元素相差的字節數)等屬性以及指向數據的存儲區域的指針data,就實現切片,所以新數組和原數組共享內存
- 當時用整數序列,整數數組和布爾數組時,不能保證數據時在數據存儲區域是等間隔的,因此無法和原始數組共享數據,只能對數據進行復制。
數組的flags屬性
CCONTIGUOUS:是否使用C語言的格式 FCONTIGUOUS:是否使用F的格式
OWNDATA:數組是否擁有數據存儲區域(True),視圖(False)
數組的轉置使用T屬性
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函數
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.]])
- 其他運算
>>> 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函數會對兩個數組的對應的元素進行計算,因此要求兩個數組形狀相同,,如果不同,會調用廣播來處理- 讓所有的數組向其中維數最多的看其,shape屬性中不足的部分加1補齊
- 輸出數組的shape屬性,是輸入數組的shape屬性的各個軸上的最大值
- 如果輸入數組的某個軸的長度為1或與輸出數組的對應軸的長度相同,這個數組能夠用來計算,否則出錯
- 當輸入數組的某個軸的長度為1時,沿着此軸運算時都用此軸的第一組值
a=np.arange(0,60,10).reshape(-1,1) b=np.arange(0,5) c=a+b
- 需要b的shape屬性向a看齊,
b.shape=1,5 - 輸出數組的各個軸的長度為輸入數組各個軸的長度的最大值,輸出數組的shape(6,5),由於b的第0軸的長度為1,而a的第0軸的長度為6, 為了讓它們在第0軸上能夠向加,需要將b的第0軸的長度擴展為6
b=b.repeat(6,axis=0)#這里的repeat()方法表示沿着axis參數指定的軸復制數組中的各個元素的值。
a=a.repeat(5,axis=1) - 經過處理后,a和b就可以進行加法運算了。當然numpy內部不會真正的用repeat進行擴展,這樣浪費內存。
因為廣播常用,所以numpyt提供ogrid對象,用於創建廣播運算用的數組
x,y=np.ogrid[:5,:5]
還提供了mgrid對象,返回的時進行廣播之后的數組 x,y=np.mgrid[:5,:5]
ogrid和多維數組一樣,用切片元祖作為下標,返回的是一組可以用來廣播計算的數組。其切片下標有兩種方式 - 開始值:結束值:步長 和np.arange()類似
- 開始值:結束值:長度j,當第三個參數為虛數時,它表示所返回的數組的長度,和np.linspace()類似包括結束值
x,y=np.ogrid[:1:4j,:1:3j]
x為0到1的4個元素的等差數列
y為0到1的3個元素的等差數列
利用ogrid的返回值,我們很容易計算二元函數在等間距網絡上的值,下面時繪制三維曲面f(x,y)=xe^(x2-y2)
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]])
龐大的函數庫
- 隨機數 from numpy import random as nr
使用numpy.set_printoptions(precision=2)可以指定小數點后保留兩位- rand 0到1之間的隨機浮點數,它的所有參數用於指定所產生的數組的形狀
r1=nr.rand(4,3) - randn()產生標准動態分布的隨機數,參數也是產生數組的形狀 r2=nr.randn(4,3)
- randint()產生指定范圍的隨機整數,包括起始值,但不包括終值 r3=nr.randint(0,10,(4,3)) random模塊提供了許多產生符合特點定隨機分布的隨機數的函數
- normal():正態分布,前兩個參數分別為期望值和標准差
r1=nr.normal(100,10,(4,3)) - uniform():均勻分布,前兩個參數分別為區間的起始值和終值
r2=nr.uniform(10,20,(4,3)) - poisson():泊松分布,第一個參數指定λ參數,他表示單位時間(或單位面積)內隨機事件的平均發生率。由於泊松分布是一個離散分布,因此他輸出的數組時一個整數數組
r3=nr.poisson(2.0,(4,3)) - permutation()可以用於生產一個亂序數組,當參數為整數n時,它返回[0,n)這n個整數的隨機排列;當參數為一個序列時,它返回一個隨機排列之后的序列:
a=np.array([1,10,20,30,40])
nr.permutation(10) nr.permutation(a) - shuffle()直接將參數數組順序打亂,permutation()返回一個新數組
nr.shuffle(a) - choice()從指定的樣本中隨機進行抽取
size參數用於指定輸出數組的形狀 replace參數為True時,進行可重復抽取,而為False時進行不重復抽取,默認值巍峨True。c1可能有重復數值,c2每隔數值都不同
p參數指定每個元素對應的抽取概率,如果不指定,所有的元素倍抽取到的概率相同。值越大的元素被抽到的概率越大,因此c3中數值較大的元素比較多
a=np.arange(10,25,dtype=float) c1=nr.choice(a,size=(4,3)) c2=nr.choice(a,size=(4,3),replace=False) c3=nr.choice(a,size=(4,3),p=a/np.sum(a)) - seed()函數指定隨機數的種子,在偽隨機數生成器里,使用seed方法可以生成固定的隨機數數組
nr.seed(10) r1=nr.randint(0,100,3)
nr.seed(10) r2=nr.randint(0,100,3)
r1和r2一樣
- rand 0到1之間的隨機浮點數,它的所有參數用於指定所產生的數組的形狀
- 求和、平均數、方差
- sum()計算數組元素之和,也可以對列表、元組等與數組類似的序列進行求和。當數組時多維時,它計算數組中所有元素的和。
np.random.seed(42)
a=np.random.randint(0,10,size=(4,5))
如果指定axis參數,則求和運算沿着指定的軸進行。結果數組為原數組的形狀去掉axis個元素
np.sum(a,axis=1)
np.sum(a,axis=0)
當axis參數時一個軸的序列時,對指定的所有軸進行求和運算。
np.sum(np.ones((2,3,4)),axis=(0,2)) array([8,8,8])
- sum()計算數組元素之和,也可以對列表、元組等與數組類似的序列進行求和。當數組時多維時,它計算數組中所有元素的和。