Python必備基礎:這些NumPy的神操作你都掌握了嗎?
導讀:NumPy是Python的基礎,更是資料科學的通用語言。
本文簡單介紹NumPy模組的兩個基本物件ndarray、ufunc,介紹ndarray物件的幾種生成方法及如何存取其元素、如何操作矩陣或多維陣列、如何進行資料合併與展平等。最後說明通用函式及廣播機制。
作者:吳茂貴,王冬,李濤,楊本法
如需轉載請聯絡大資料(ID:hzdashuju)
NumPy為何如此重要?實際上Python本身含有列表(list)和陣列(array),但對於大資料來說,這些結構有很多不足。因列表的元素可以是任何物件,因此列表中所儲存的是物件的指標。這樣為了儲存一個簡單的[1,2,3],都需要有3個指標和3個整數物件。
對於數值運算來說,這種結構顯然比較浪費記憶體和CPU計算時間。至於array物件,它直接儲存數值,和C語言的一維陣列比較類似。但是由於它不支援多維,也沒有各種運算函式,因此也不適合做數值運算。
NumPy(Numerical Python 的簡稱)的誕生彌補了這些不足,它提供了兩種基本的物件:ndarray(N-dimensional array object)和 ufunc(universal function object)。ndarray是儲存單一資料型別的多維陣列,而ufunc則是能夠對陣列進行處理的函式。
NumPy的主要特點:
- ndarray,快速,節省空間的多維陣列,提供陣列化的算術運算和高階的廣播功能。
- 使用標準數學函式對整個陣列的資料進行快速運算,而不需要編寫迴圈。
- 讀取/寫入磁碟上的陣列資料和操作儲存器映像檔案的工具。
- 線性代數,隨機數生成,以及傅立葉變換的能力。
- 整合C、C++、Fortran程式碼的工具。
在使用 NumPy 之前,需要先匯入該模組:
import numpy as np
01 生成ndarray的幾種方式
NumPy封裝了一個新的資料型別ndarray,一個多維陣列物件,該物件封裝了許多常用的數學運算函式,方便我們進行資料處理以及資料分析,那麼如何生成ndarray呢?這裡我們介紹生成ndarray的幾種方式,如從已有資料中建立;利用random建立;建立特殊多維陣列;使用arange函式等。
1. 從已有資料中建立
直接對python的基礎資料型別(如列表、元組等)進行轉換來生成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
在深度學習中,我們經常需要對一些變數進行初始化,適當的初始化能提高模型的效能。通常我們用隨機數生成模組random來生成,當然random模組又分為多種函式:
- random生成0到1之間的隨機數;
- uniform生成均勻分佈隨機數;
- randn生成標準正態的隨機數;
- normal生成正態分佈;
- shuffle隨機打亂順序;
- seed設定隨機數種子等。
下面我們列舉幾個簡單示例。
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'>
生成一個隨機種子,對生成的隨機數打亂。
import numpy as np np.random.seed(123) nd5_1 = np.random.randn(2,3) print(nd5_1) np.random.shuffle(nd5_1) print("隨機打亂後資料") print(nd5_1) print(type(nd5_1))
列印結果:
[[-1.0856306 0.99734545 0.2829785 ] [-1.50629471 -0.57860025 1.65143654]]
隨機打亂後資料為:
[[-1.50629471 -0.57860025 1.65143654] [-1.0856306 0.99734545 0.2829785 ]] <class 'numpy.ndarray'>
3. 建立特定形狀的多維陣列
資料初始化時,有時需要生成一些特殊矩陣,如0或1的陣列或矩陣,這時我們可以利用np.zeros、np.ones、np.diag來實現,下面我們通過幾個示例來說明。
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]))
我們還可以把生成的資料儲存到磁碟,然後從磁碟讀取。
import numpy as np nd9 = np.random.random([5,5]) np.savetxt(X=nd9,fname='./test2.txt') nd10 = np.loadtxt('./test2.txt')
4. 利用arange函式
arange是numpy模組中的函式,其格式為:arange([start,] stop[, step,], dtype=None)。根據start與stop指定的範圍,以及step設定的步長,生成一個 ndarray,其中start預設為0,步長step可為小數。
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 存取元素
上節我們介紹了生成ndarray的幾種方法,資料生成後,如何讀取我們需要的資料?這節我們介紹幾種讀取資料的方法。
import numpy as np np.random.seed(2018) nd11 = np.random.random([10]) #獲取指定位置的資料,獲取第4個元素 nd11[3] #擷取一段資料 nd11[3:6] #擷取固定間隔資料 nd11[1:6:2] #倒序取數 nd11[::-2] #擷取一個多維陣列的一個區域內資料 nd12=np.arange(25).reshape([5,5]) nd12[1:3,1:3] #擷取一個多維陣列中,數值在一個值域之內的資料 nd12[(nd12>3)&(nd12<10)] #擷取多維陣列中,指定的行,如讀取第2,3行 nd12[[1,2]] #或nd12[1:3,:] ##擷取多維陣列中,指定的列,如讀取第2,3列 nd12[:,1:3]
如果你對上面這些獲取方式還不是很清楚,沒關係,下面我們通過圖形的方式說明如何獲取多維陣列中的元素,如圖1-1所示,左邊為表示式,右邊為對應獲取元素。
▲圖1-1 獲取多維陣列中的元素
獲取陣列中的部分元素除通過指定索引標籤外,還可以使用一些函式來實現,如通過random.choice函式從指定的樣本中進行隨機抽取資料。
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指定輸出陣列形狀 c2=nr.choice(a,size=(3,4),replace=False) #replace預設為True,即可重複抽取 #下式中引數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 矩陣操作
深度學習中經常涉及多維陣列或矩陣的運算,正好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模組中的函式,numpy.linalg模組中的函式是滿足行業標準級的Fortran庫。
numpy.linalg中常用函式:
- diag:以一維陣列方式返回方陣的對角線元素
- dot:矩陣乘法
- trace:求跡,即計算對角線元素的和
- det:計算矩陣列式
- eig:計算方陣的本徵值和本徵向量
- inv:計算方陣的逆
- qr:計算qr分解
- svd:計算奇異值分解svd
- solve:解線性方程組Ax = b,其中A為方陣
- lstsq:計算Ax=b的最小二乘解
04 資料合併與展平
在機器學習或深度學習中,會經常遇到需要把多個向量或矩陣按某軸方向進行合併的情況,也會遇到展平的情況,如在卷積或迴圈神經網路中,在全連線層之前,需要把矩陣展平。這節介紹幾種資料合併和展平的方法。
1. 合併一維陣列
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. 多維陣列的合併
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("合併後資料維度",c.shape) #按列合併 d=np.append(a,b,axis=1) print("按列合併結果:") print(d) print("合併後資料維度",d.shape)
列印結果:
[[0 1] [2 3] [0 1] [2 3]] 合併後資料維度 (4, 2) 按列合併結果: [[0 1 0 1] [2 3 2 3]] 合併後資料維度 (2, 4)
3. 矩陣展平
import numpy as np nd15=np.arange(6).reshape(2,-1) print(nd15) #按照列優先,展平。 print("按列優先,展平") print(nd15.ravel('F')) #按照行優先,展平。 print("按行優先,展平") print(nd15.ravel())
列印結果:
[[0 1 2] [3 4 5]] 按列優先,展平 [0 3 1 4 2 5] 按行優先,展平 [0 1 2 3 4 5]
05 通用函式
NumPy提供了兩種基本的物件,即ndarray和ufunc物件。前面我們對ndarray做了簡單介紹,本節將介紹它的另一個物件ufunc。
ufunc(通用函式)是universal function的縮寫,它是一種能對陣列的每個元素進行操作的函式。許多ufunc函式都是在C語言級別實現的,因此它們的計算速度非常快。
此外,功能比math模組中的函式更靈活。math模組的輸入一般是標量,但NumPy中的函式可以是向量或矩陣,而利用向量或矩陣可以避免迴圈語句,這點在機器學習、深度學習中經常使用。以下為NumPy中的常用幾個通用函式:
- sqrt:計算序列化資料的平方根
- sin,cos:三角函式
- abs:計算序列化資料的絕對值
- dot:矩陣運算
- log,log10,log2:對數函式
- exp:指數函式
- cumsum,cumproduct:累計求和,求積
- sum:對一個序列化資料進行求和
- mean:計算均值
- median:計算中位數
- std:計算標準差
- var:計算方差
- corrcoef:計算相關係數
1. 使用math與numpy函式效能比較
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. 使用迴圈與向量運算比較
充分使用Python的NumPy庫中的內建函式(built-in function),實現計算的向量化,可大大提高執行速度。NumPy庫中的內建函式使用了SIMD指令。例如下面所示在Python中使用向量化要比使用迴圈計算速度快得多。
import time import numpy as np x1 = np.random.rand(1000000) x2 = np.random.rand(1000000) ##使用迴圈計算向量點積 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) + " for loop----- Computation time = " + str(1000*(toc - tic)) + "ms") ##使用numpy函式求點積 tic = time.process_time() dot = 0 dot = np.dot(x1,x2) toc = time.process_time() print ("dot = " + str(dot) + " 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迴圈的執行時間是使用向量運算的執行時間的約400倍。因此,深度學習演算法中,一般都使用向量化矩陣運算。
06 廣播機制
廣播機制(Broadcasting)的功能是為了方便不同shape的陣列(NumPy庫的核心資料結構)進行數學運算。廣播提供了一種向量化陣列操作的方法,以便在C中而不是在Python中進行迴圈,這通常會帶來更高效的演算法實現。廣播的相容原則為:
- 對齊尾部維度。
- shape相等or其中shape元素中有一個為1。
以下通過例項來具體說明。
import numpy as np a=np.arange(10) b=np.arange(10) #兩個shape相同的陣列相加 print(a+b) #一個陣列與標量相加 print(a+3) #兩個向量相乘 print(a*b) #多維陣列之間的運算 c=np.arange(10).reshape([5,2]) d=np.arange(2).reshape([1,2]) #首先將d陣列進行復制擴充為[5,2],如何複製請參考圖1-2,然後相加。 print(c+d)
▲圖1-2 NumPy多維陣列相加
列印結果:
[ 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()函式來變更矩陣的維度。
07 小結
閱讀完本文,你已get到如下技能:
√ 如何生成NumPy的ndarray的幾種方式。
√ 如何存取元素。
√ 如何操作矩陣。
√ 如何合併或拆分資料。
√ NumPy的通用函式。
√ NumPy的廣播機制。
如果想進一步瞭解NumPy,大家可參考:
http://www.numpy.org/
關於作者:吳茂貴,BI和大資料專家,就職於中國外匯交易中心,在BI、資料探勘與分析、資料倉儲、機器學習等領域有超過20年的工作經驗,在Spark機器學習、TensorFlow深度學習領域大量的實踐經驗。
王冬,任職於博世(中國)投資有限公司,負責Bosch企業BI及工業4.0相關大資料和資料探勘專案。對機器學習、人工智慧有多年實踐經驗。
李濤,參與過多個人工智慧專案,如研究開發服務機器人、無人售後店等專案。熟悉python、caffe、TensorFlow等,對深度學習、尤其對計算機視覺方面有較深理解。
楊本法,高階演算法工程師,在機器學習、文字挖掘、視覺化等領域有多年實踐經驗。熟悉Hadoop、Spark生態圈的相關技術,對Python有豐富的實戰經驗。
本文摘編自《Python深度學習:基於TensorFlow》,經出版方授權釋出。
延伸閱讀《Python深度學習:基於TensorFlow》
推薦語:從Python和數學,到機器學習和TensorFlow,再到深度學習的應用和擴充套件,為深度學習提供全棧解決方案。
相關文章
- 這些必備Java技能,你都會了嗎Java
- Python操作MySQL儲存,這些你都會了嗎?PythonMySql
- 做java的你,這些英文單詞都掌握了嗎?Java
- 這些必會的計算機網路知識點你都掌握了嗎計算機網路
- 10道Python基礎面試題附答案,你都掌握了嗎?Python面試題
- 這些喜聞樂見的Java面試知識點,你都掌握了嗎?Java面試
- 學習Linux,這些命令你都掌握了嗎?Linux
- 這些Python騷操作,你知道嗎?Python
- Chrome DevTools中的這些騷操作,你都知道嗎?Chromedev
- 學了Python能做什麼 都需要掌握這些技能Python
- 新媒體入門操作?這些關鍵點你都學會了嗎?
- 面試現場!月薪3w+的這些資料探勘SQL面試題你都掌握了嗎?SQL面試題
- 面試官帶你學Android——面試中Handler 這些必備知識點你都知道嗎?面試Android
- java web開發這些細節你真的掌握了嗎JavaWeb
- 學習Python這些面試題你都知道嗎?Python面試題
- python是什麼?這些你都瞭解了嗎?Python
- 面試現場:這些常問的面試題你都會了嗎面試題
- Python的十七個騷操作,你都學會了嗎?(上)Python
- 別再眼高手低了! 這些Linq方法都清楚地掌握了嗎?
- Java面試必問面試題,你掌握了嗎?Java面試題
- 這些鮮為人知的前端冷知識,你都GET了嗎?前端
- 金三銀四跳槽季,這些面試題你都會了嗎?面試題
- 小特性 大用途 —— YashanDB JDBC驅動的這些特性你都get了嗎?JDBC
- Java8的這些集合騷操作,你掌握了嘛?Java
- 收藏!這些 IDE 使用技巧,你都知道嗎IDE
- Nacos必知必會:這些知識點你一定要掌握!
- 這些操作刪除console.log程式碼,你都知道嗎
- ES6的這些操作技巧,你會嗎?
- 學習網路安全,這些必備基礎知識不能少!
- 這些高階的函式技術,你掌握了麼函式
- Python科學計算庫NumPy基礎操作Python
- 效能測試的分類、區別以及特點這些你都知道了嗎?
- 自媒體必備工具我都幫你整理好了,這些工具讓你省心又省事
- 關於Linux系統,這些你都知道嗎?Linux
- 這 20 多個高併發程式設計必備的知識點,你都會嗎?程式設計
- 消除遊戲美術設計的這些套路,你都知道嗎?遊戲
- 超好用的macOS Monterey 隱藏功能,這些你都知道嗎Mac
- 讓iOS保持介面流暢的這些技巧,你都知道嗎iOS