作者:吳茂貴,,王冬,李濤,,楊本法 如需轉載請聯(lián)系大數(shù)據(jù)(ID:hzdashuju) NumPy為何如此重要?實際上Python本身含有列表(list)和數(shù)組(array),,但對于大數(shù)據(jù)來說,,這些結構有很多不足。因列表的元素可以是任何對象,,因此列表中所保存的是對象的指針,。這樣為了保存一個簡單的[1,2,3],,都需要有3個指針和3個整數(shù)對象。 對于數(shù)值運算來說,,這種結構顯然比較浪費內存和CPU計算時間,。至于array對象,它直接保存數(shù)值,,和C語言的一維數(shù)組比較類似,。但是由于它不支持多維,也沒有各種運算函數(shù),,因此也不適合做數(shù)值運算,。 NumPy(Numerical Python 的簡稱)的誕生彌補了這些不足,它提供了兩種基本的對象:ndarray(N-dimensional array object)和 ufunc(universal function object),。ndarray是存儲單一數(shù)據(jù)類型的多維數(shù)組,,而ufunc則是能夠對數(shù)組進行處理的函數(shù)。 NumPy的主要特點:
在使用 NumPy 之前,,需要先導入該模塊: import numpy as np
01 生成ndarray的幾種方式NumPy封裝了一個新的數(shù)據(jù)類型ndarray,一個多維數(shù)組對象,,該對象封裝了許多常用的數(shù)學運算函數(shù),,方便我們進行數(shù)據(jù)處理以及數(shù)據(jù)分析,那么如何生成ndarray呢,?這里我們介紹生成ndarray的幾種方式,,如從已有數(shù)據(jù)中創(chuàng)建;利用random創(chuàng)建,;創(chuàng)建特殊多維數(shù)組,;使用arange函數(shù)等。 1. 從已有數(shù)據(jù)中創(chuàng)建 直接對python的基礎數(shù)據(jù)類型(如列表,、元組等)進行轉換來生成ndarray,。 (1)將列表轉換成ndarray import numpy as np list1 = [3.14,2.17,0,1,2] nd1 = np.array(list1) print(nd1) print(type(nd1)) 打印結果: [ 3.14 2.17 0. 1. 2. ]
<class 'numpy.ndarray'>
(2)嵌套列表可以轉換成多維ndarray import numpy as np list2 = [[3.14,2.17,0,1,2],[1,2,3,4,5]] nd2 = np.array(list2) print(nd2) print(type(nd2)) 打印結果: [[ 3.14 2.17 0. 1. 2. ]
[ 1. 2. 3. 4. 5. ]]
<class 'numpy.ndarray'>
如果把(1)和(2)中的列表換成元組也同樣適合,。 2. 利用random模塊生成ndarray 在深度學習中,我們經(jīng)常需要對一些變量進行初始化,,適當?shù)某跏蓟芴岣吣P偷男阅?。通常我們用隨機數(shù)生成模塊random來生成,當然random模塊又分為多種函數(shù):
下面我們列舉幾個簡單示例,。 import numpy as np nd5 = np.random.random([3,3]) print(nd5) print(type(nd5)) 打印結果: [[ 0.88900951 0.47818541 0.91813526]
[ 0.48329167 0.63730656 0.14301479]
[ 0.9843789 0.99257093 0.24003961]]
<class 'numpy.ndarray'>
生成一個隨機種子,對生成的隨機數(shù)打亂,。 import numpy as np np.random.seed(123) nd5_1 = np.random.randn(2,3) print(nd5_1) np.random.shuffle(nd5_1) print('隨機打亂后數(shù)據(jù)') print(nd5_1) print(type(nd5_1)) 打印結果: [[-1.0856306 0.99734545 0.2829785 ]
[-1.50629471 -0.57860025 1.65143654]]
隨機打亂后數(shù)據(jù)為: [[-1.50629471 -0.57860025 1.65143654] [-1.0856306 0.99734545 0.2829785 ]] <class 'numpy.ndarray'> 3. 創(chuàng)建特定形狀的多維數(shù)組 數(shù)據(jù)初始化時,,有時需要生成一些特殊矩陣,如0或1的數(shù)組或矩陣,,這時我們可以利用np.zeros,、np.ones、np.diag來實現(xiàn),,下面我們通過幾個示例來說明,。 import numpy as np
#生成全是0的3x3矩陣
nd6 = np.zeros([3,3])
#生成全是1的3x3矩陣
nd7 = np.ones([3,3])
#生成3階的單位矩陣
nd8= np.eye(3)
#生成3階對角矩陣
print (np.diag([1, 2, 3]))
我們還可以把生成的數(shù)據(jù)保存到磁盤,然后從磁盤讀取,。 import numpy as np nd9 = np.random.random([5,5]) np.savetxt(X=nd9,fname='./test2.txt') nd10 = np.loadtxt('./test2.txt') 4. 利用arange函數(shù) arange是numpy模塊中的函數(shù),,其格式為:arange([start,] stop[, step,], dtype=None)。根據(jù)start與stop指定的范圍,,以及step設定的步長,,生成一個 ndarray,其中start默認為0,,步長step可為小數(shù),。 import numpy as np
print(np.arange(10))
print(np.arange(0,10))
print(np.arange(1, 4,0.5))
print(np.arange(9, -1, -1))
02 存取元素上節(jié)我們介紹了生成ndarray的幾種方法,數(shù)據(jù)生成后,,如何讀取我們需要的數(shù)據(jù),?這節(jié)我們介紹幾種讀取數(shù)據(jù)的方法。 import numpy as np np.random.seed(2018) nd11 = np.random.random([10]) #獲取指定位置的數(shù)據(jù),,獲取第4個元素 nd11[3] #截取一段數(shù)據(jù) nd11[3:6] #截取固定間隔數(shù)據(jù) nd11[1:6:2] #倒序取數(shù) nd11[::-2] #截取一個多維數(shù)組的一個區(qū)域內數(shù)據(jù) nd12=np.arange(25).reshape([5,5]) nd12[1:3,1:3] #截取一個多維數(shù)組中,,數(shù)值在一個值域之內的數(shù)據(jù) nd12[(nd12>3)&(nd12<10)] #截取多維數(shù)組中,指定的行,如讀取第2,3行 nd12[[1,2]] #或nd12[1:3,:] ##截取多維數(shù)組中,,指定的列,如讀取第2,3列 nd12[:,1:3] 如果你對上面這些獲取方式還不是很清楚,,沒關系,,下面我們通過圖形的方式說明如何獲取多維數(shù)組中的元素,如圖1-1所示,,左邊為表達式,,右邊為對應獲取元素。 ▲圖1-1 獲取多維數(shù)組中的元素 獲取數(shù)組中的部分元素除通過指定索引標簽外,,還可以使用一些函數(shù)來實現(xiàn),如通過random.choice函數(shù)從指定的樣本中進行隨機抽取數(shù)據(jù),。 import numpy as np
from numpy import random as nr
a=np.arange(1,25,dtype=float)
c1=nr.choice(a,size=(3,4)) #size指定輸出數(shù)組形狀
c2=nr.choice(a,size=(3,4),replace=False) #replace缺省為True,,即可重復抽取
#下式中參數(shù)p指定每個元素對應的抽取概率,默認為每個元素被抽取的概率相同
c3=nr.choice(a,size=(3,4),p=a / np.sum(a))
print('隨機可重復抽取')
print(c1)
print('隨機但不重復抽取')
print(c2)
print('隨機但按制度概率抽取')
print(c3)
打印結果: 隨機可重復抽取 [[ 7. 22. 19. 21.] [ 7. 5. 5. 5.] [ 7. 9. 22. 12.]] 隨機但不重復抽取 [[ 21. 9. 15. 4.] [ 23. 2. 3. 7.] [ 13. 5. 6. 1.]] 隨機但按制度概率抽取 [[ 15. 19. 24. 8.] [ 5. 22. 5. 14.] [ 3. 22. 13. 17.]] 03 矩陣操作深度學習中經(jīng)常涉及多維數(shù)組或矩陣的運算,,正好NumPy模塊提供了許多相關的計算方法,,下面介紹一些常用的方法。 import numpy as np
nd14=np.arange(9).reshape([3,3])
#矩陣轉置
np.transpose(nd14)
#矩陣乘法運算
a=np.arange(12).reshape([3,4])
b=np.arange(8).reshape([4,2])
a.dot(b)
#求矩陣的跡
a.trace()
#計算矩陣行列式
np.linalg.det(nd14)
#計算逆矩陣
c=np.random.random([3,3])
np.linalg.solve(c,np.eye(3))
上面介紹的幾種方法是numpy.linalg模塊中的函數(shù),,numpy.linalg模塊中的函數(shù)是滿足行業(yè)標準級的Fortran庫,。 numpy.linalg中常用函數(shù):
04 數(shù)據(jù)合并與展平在機器學習或深度學習中,,會經(jīng)常遇到需要把多個向量或矩陣按某軸方向進行合并的情況,也會遇到展平的情況,,如在卷積或循環(huán)神經(jīng)網(wǎng)絡中,,在全連接層之前,需要把矩陣展平,。這節(jié)介紹幾種數(shù)據(jù)合并和展平的方法,。 1. 合并一維數(shù)組 import numpy as np a=np.array([1,2,3]) b=np.array([4,5,6]) c=np.append(a,b) print(c) #或利用concatenate d=np.concatenate([a,b]) print(d) 打印結果: [1 2 3 4 5 6]
[1 2 3 4 5 6]
2. 多維數(shù)組的合并 import numpy as np a=np.arange(4).reshape(2,2) b=np.arange(4).reshape(2,2) #按行合并 c=np.append(a,b,axis=0) print(c) print('合并后數(shù)據(jù)維度',c.shape) #按列合并 d=np.append(a,b,axis=1) print('按列合并結果:') print(d) print('合并后數(shù)據(jù)維度',d.shape) 打印結果: [[0 1]
[2 3]
[0 1]
[2 3]]
合并后數(shù)據(jù)維度 (4, 2)
按列合并結果:
[[0 1 0 1]
[2 3 2 3]]
合并后數(shù)據(jù)維度 (2, 4)
3. 矩陣展平 import numpy as np nd15=np.arange(6).reshape(2,-1) print(nd15) #按照列優(yōu)先,展平,。 print('按列優(yōu)先,展平') print(nd15.ravel('F')) #按照行優(yōu)先,,展平。 print('按行優(yōu)先,展平') print(nd15.ravel()) 打印結果: [[0 1 2]
[3 4 5]]
按列優(yōu)先,展平
[0 3 1 4 2 5]
按行優(yōu)先,展平
[0 1 2 3 4 5]
05 通用函數(shù)NumPy提供了兩種基本的對象,,即ndarray和ufunc對象,。前面我們對ndarray做了簡單介紹,本節(jié)將介紹它的另一個對象ufunc,。 ufunc(通用函數(shù))是universal function的縮寫,,它是一種能對數(shù)組的每個元素進行操作的函數(shù)。許多ufunc函數(shù)都是在C語言級別實現(xiàn)的,,因此它們的計算速度非??臁?/p> 此外,,功能比math模塊中的函數(shù)更靈活,。math模塊的輸入一般是標量,,但NumPy中的函數(shù)可以是向量或矩陣,而利用向量或矩陣可以避免循環(huán)語句,,這點在機器學習,、深度學習中經(jīng)常使用。以下為NumPy中的常用幾個通用函數(shù):
1. 使用math與numpy函數(shù)性能比較 import time import math import numpy as np x = [i * 0.001 for i in np.arange(1000000)] start = time.clock() for i, t in enumerate(x): x[i] = math.sin(t) print ('math.sin:', time.clock() - start ) x = [i * 0.001 for i in np.arange(1000000)] x = np.array(x) start = time.clock() np.sin(x) print ('numpy.sin:', time.clock() - start ) 打印結果: math.sin: 0.5169950000000005
numpy.sin: 0.05381199999999886
由此可見,,numpy.sin比math.sin快近10倍。 2. 使用循環(huán)與向量運算比較 充分使用Python的NumPy庫中的內建函數(shù)(built-in function),,實現(xiàn)計算的向量化,,可大大提高運行速度。NumPy庫中的內建函數(shù)使用了SIMD指令,。例如下面所示在Python中使用向量化要比使用循環(huán)計算速度快得多,。 import time import numpy as np x1 = np.random.rand(1000000) x2 = np.random.rand(1000000) ##使用循環(huán)計算向量點積 tic = time.process_time() dot = 0 for i in range(len(x1)): dot = x1[i]*x2[i] toc = time.process_time() print ('dot = ' str(dot) '\n for loop----- Computation time = ' str(1000*(toc - tic)) 'ms') ##使用numpy函數(shù)求點積 tic = time.process_time() dot = 0 dot = np.dot(x1,x2) toc = time.process_time() print ('dot = ' str(dot) '\n verctor version---- Computation time = ' str(1000*(toc - tic)) 'ms') 打印結果: dot = 250215.601995
for loop----- Computation time = 798.3389819999998ms
dot = 250215.601995
verctor version---- Computation time = 1.885051999999554ms
從程序運行結果上來看,該例子使用for循環(huán)的運行時間是使用向量運算的運行時間的約400倍,。因此,,深度學習算法中,,一般都使用向量化矩陣運算,。 06 廣播機制廣播機制(Broadcasting)的功能是為了方便不同shape的數(shù)組(NumPy庫的核心數(shù)據(jù)結構)進行數(shù)學運算。廣播提供了一種向量化數(shù)組操作的方法,,以便在C中而不是在Python中進行循環(huán),,這通常會帶來更高效的算法實現(xiàn)。廣播的兼容原則為:
以下通過實例來具體說明。 import numpy as np a=np.arange(10) b=np.arange(10) #兩個shape相同的數(shù)組相加 print(a b) #一個數(shù)組與標量相加 print(a 3) #兩個向量相乘 print(a*b) #多維數(shù)組之間的運算 c=np.arange(10).reshape([5,2]) d=np.arange(2).reshape([1,2]) #首先將d數(shù)組進行復制擴充為[5,2],如何復制請參考圖1-2,,然后相加,。 print(c d) ▲圖1-2 NumPy多維數(shù)組相加 打印結果: [ 0 2 4 6 8 10 12 14 16 18]
[ 3 4 5 6 7 8 9 10 11 12]
[ 0 1 4 9 16 25 36 49 64 81]
[[ 0 2]
[ 2 4]
[ 4 6]
[ 6 8]
[ 8 10]]
有時為了保證矩陣運算正確,,我們可以使用reshape()函數(shù)來變更矩陣的維度,。 07 小結閱讀完本文,你已get到如下技能: √ 如何生成NumPy的ndarray的幾種方式,。 √ 如何存取元素,。 √ 如何操作矩陣。 √ 如何合并或拆分數(shù)據(jù),。 √ NumPy的通用函數(shù),。 √ NumPy的廣播機制。
|
|