嗨,大家好,我是Teresa,這集想來和大家介紹在資料分析、機器學習領域中很經典、必定會用到的函式庫-Numpy,目的主要是做數據的處理,但內容不會涉及統計的理論和延伸,只會做一些基礎的功能介紹和簡易的實作程式碼提供給大家。
什麼是Numpy?
Numpy是一個免費且開源的Python函式庫,專門用來處理陣列,由Travis Oliphant於2005年創建,但Numpy的前身是Numeric,是由Jim Hugunin和其他協作者共同開發,Numpy結合另一個同性質程式庫Numarray的特色,並加入了其他擴充功能。原始碼在這個網站中:https://github.com/numpy/numpy
為什麼使用Numpy?
在Python中,我們也有list來存放清單,但其實處理速度很慢,Numpy處理陣列的速度比list快50倍。原因是Numpy會將資料儲存在記憶體中的一個連續位置,可以高效率的找到他們的位置、並使用資料。
安裝Numpy
pip install numpy import numpy #測試程式碼 arr = numpy.array([1, 2, 3, 4, 5]) print(arr)
#如果覺得每次都要輸入numpy很麻煩,在匯入的時候可以輸入: import numpy as np arr = np.array([1, 2, 3, 4, 5])
建立陣列
Numpy的陣列稱為ndarray,創建陣列的函數為:ndarray array( )
arr0 = np.array(40) print(arr0) #只有一個元素的陣列 arr1 = np, array([1, 2, 3, 4, 5]) print(arr1) #稱為單維或一維的陣列,裡面的值包含1, 2, 3, 4, 5 arr2 = np.array([[1, 2, 3], [4, 5, 6]]) print(arr2) #包含一個以上的一維陣列稱為二維陣列,可用來表示矩陣 arr3 = np. array([[[1, 2, 3], [4, 5, 6]], [[ 1, 2, 3], [4, 5, 6]]]) print(arr3) #包含一個以上的二維陣列稱為三維陣列
利用函數ndim 可以得知陣列有幾個維度
arr0 = np.array(40) arr1 = np, array([1, 2, 3, 4, 5]) arr2 = np.array([[1, 2, 3], [4, 5, 6]]) arr3 = np. array([[[1, 2, 3], [4, 5, 6]], [[ 1, 2, 3], [4, 5, 6]]]) print(arr0.ndim) #0 print(arr1.ndim) #1 print(arr2.ndim) #2 print(arr3.ndim) #3
陣列可以有任何數的維度,可以用ndmin來定義維度的數量
arr = np.array([1, 2, 3, 4], admin = 5) print(arr) print(“此陣列為", arr.ndim, “維度")
陣列的大小
利用shape可以得到陣列是以幾個維度、幾個元素所組成
arr = np.array([[1, 2, 3, 4], [5, 6, 7, 8]]) print(arr.shape) #(2, 4),兩個維度,每個維度有4個元素
重塑陣列
利用reshape可以改變陣列的大小
只要陣列大小中的元素相等,我們可以將陣列重塑成各種形狀
arr = np.array([1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]) newarr = arr.reshape(4, 3) #4個陣列,每個陣列有3個元素 print(newarr) #[[ 1 2 3] [ 4 5 6] [ 7 8 9] [10 11 12]] newarr1 = arr.reshape(2, 3, 2) #2個維度,每個維度2個陣列,每個陣列2個元素 print(newarr1) #[[[ 1 2] [ 3 4] [ 5 6]] [[ 7 8] [ 9 10] [11 12]]]
假設陣列中的元素很多,可以只指定要重塑成幾維度和幾個陣列,元素個數可用-1取代
arr = np.array([1, 2, 3, 4, 5, 6, 7, 8]) newarr = arr.reshape(2, 2, -1) print(newarr) #[[[1 2] [3 4]] [[5 6] [7 8]]]
如果想要把陣列展開,可以利用reshape(-1)
arr = np.array([[1, 2, 3], [4, 5, 6]]) newarr = arr.reshape(-1) print(newarr) #[1 2 3 4 5 6]
索引陣列
如果還記得我曾在字串中提到索引的概念,也同樣可以套用在這裡
再次提醒,索引值是從0開始
arr = np.array([1, 2, 3, 4]) print(arr[0]) #1 print(arr[0]) #2 print(arr[2] + print(arr[3])) #7,取得陣列中第3和第4個元素並相加
如果想要索引二維或三維陣列中的元素,可以用逗號分隔 [ 陣列, 元素]
arr2 = np.array([[1,2,3,4,5], [6,7,8,9,10]]) print("第一個陣列的第二個元素是: ", arr2[0, 1]) #2 print("第二個陣列的第五個元素是: ", arr2[1, 4]) #10
索引三維陣列:[第幾維度, 陣列, 元素]
arr3 = np.array([[[1, 2, 3], [4, 5, 6]], [[7, 8, 9], [10, 11, 12]]]) print(arr3[0, 1, 2]) #6
負索引:-1 表示從最後一個元素開始
arr2 = np.array([[1,2,3,4,5], [6,7,8,9,10]]) print("第一個陣列的第二個元素是: ", arr2[1, -1]) #10
切片陣列
切片可以把陣列從某個元素索引到某個元素,[開始:結束:步數]
注意:切片的結果會包含開始,不包含結束
arr = np.array([1, 2, 3, 4, 5, 6, 7]) print(arr[1:5]) #步數預設為1,切片結果:[2,3, 4, 5] print(arr[4:]) #從第5個元素,切到最後一個元素,結果:[5, 6, 7] print(arr[:4]) #從第一個元素,切到第4-1個元素,結果:[1, 2, 3, 4] print(arr[-3:-1]) #運用負索引的概念,結果:[5, 6] print(arr[1:5:2]) #結果:[2, 4] print(arr[::2]) #結果:[1, 3, 5, 7]
如果是要切片二維陣列 [ 陣列,開始:結束:步數]
arr = np.array([[1, 2, 3, 4, 5], [6, 7, 8, 9, 10]]) print(arr[1, 1:4]) #[7, 8, 9]
複製與檢視陣列
複製(copy)陣列後,對複本有所更改都不會影響原始陣列;相反地,對原始陣列做任何更改也不會影響複本。
檢視(view)陣列的話,對陣列有所更改,將會影響到原始陣列的數據,需特別注意。
arr = np.array([1, 2, 3, 4, 5]) x = arr.copy() arr[0] = 42 print(arr) #[42, 2, 3, 4, 5] print(x) #[1, 2, 3, 4, 5],對複本沒有影響
arr = np.array([1, 2, 3, 4, 5]) x = arr.view() x[0] = 31 print(arr) #[31, 2, 3, 4, 5] print(x) #[31, 2, 3, 4, 5],改變原始陣列也改變檢視中的陣列
要如何判斷陣列是不是會被改變? 利用函數 base
arr = np.array([1, 2, 3, 4, 5]) x = arr.copy() y = arr.view() print(x.base) #None,表示屬於一個新的陣列,不會改變原始陣列 print(y.base) #[1, 2, 3, 4, 5],表示數據來自此陣列,修改後原始陣列也會受影響
遍歷陣列
如果要運用到陣列中的每一個元素,以for迴圈來寫,會讓程式碼變得非常複雜
我們可以使用nditer( )來達到同樣的效果
arr = np.array([[[1, 2], [3, 4]], [[5, 6], [7, 8]]]) for x in np.nditer(arr): print(x) #1 2 3 4 5 6 7 8 for y in np.nditer(arr[:, ::2]): #運用索引的概念 print(y) #1, 3, 5, 7
使用ndenumerate( )可以讓輸出的結果包含元素的索引號
arr = np.array([1, 2, 3]) for idx, x in np.ndenumerate(arr): print(idx, x) #(0,) 1 (1,) 2 (2,) 3 arr1 = np.array([[1, 2, 3, 4], [5, 6, 7, 8]]) for idx, y in np.ndenumerate(arr1): print(idx, y) #(0, 0) 1 (0, 1) 2 (0, 2) 3 (0, 3) 4 #(1, 0) 5 (1, 1) 6 (1, 2) 7 (1, 3) 8
串聯陣列
利用concatenate(陣列,陣列,軸)可以把兩個或多個陣列放在同一個陣列中,軸預設值為0
arr1 = np.array([1, 2, 3]) arr2 = np.array([4, 5, 6]) arr = np.concatenate((arr1, arr2)) print(arr) #[1 2 3 4 5 6] arr3 = np.array([[1, 2], [3, 4]]) arr4 = np.array([[5, 6], [7, 8]]) arr = np.concatenate((arr3, arr4), axis=1) #軸= 1表示二維陣列 print(arr) #[[1 2 5 6] [3 4 7 8]]
利用stack( )可以沿著所指定的軸將值堆疊上去
hstack( ):沿著行堆疊
vstack( ):沿著列堆疊
dstack( ):沿著高度堆疊
arr1 = np.array([1, 2, 3]) arr2 = np.array([4, 5, 6]) arr = np.stack((arr1, arr2), axis=1) print(arr) #[[1 4] [2 5] [3 6]] arr = np.hstack((arr1, arr2)) print(arr) #[1 2 3 4 5 6] arr = np.vstack((arr1, arr2)) print(arr) #[[1 2 3] [4 5 6]] arr = np.dstack((arr1, arr2)) print(arr) #[[[1 4] [2 5] [3 6]]]
分割陣列
分割是串聯的反向操作,利用array_split( )可以將一個陣列分割成多個陣列,一二三維度同理
arr = np.array([1, 2, 3, 4, 5, 6]) newarr = np.array_split(arr, 3) print(newarr) #[array([1, 2]), array([3, 4]), array([5, 6])] print(newarr[0]) #[1, 2] print(newarr[1]) #[3, 4] print(newarr[2]) #[5, 6]
陣列排序
利用sort( )可將陣列排序,會生成複製的陣列,不會影響到原始的陣列
arr = np.array([3, 2, 0, 1]) print(np.sort(arr)) #[0, 1, 2, 3] arr1 = np.array([[3, 2, 4], [5, 0, 1]]) print(np.sort(arr1)) #[[2 3 4] [0 1 5]] arr2 = np.array(['banana', 'cherry', 'apple']) print(np.sort(arr2)) #['apple' 'banana' 'cherry'],依照ASCII碼大小排列 arr3 = np.array([True, False, True]) print(np.sort(arr3)) #[False True True],依照ASCII碼大小排列
搜尋陣列
利用where( )可以尋找陣列中的某個值並回傳相對應元素的索引值
arr = np.array([1, 2, 3, 4, 5, 4, 4]) x = np.where(arr == 4) print(x) #(array([3, 5, 6],) arr1 = np.array([1, 2, 3, 4, 5, 6, 7, 8]) x = np.where(arr1%2 == 0) #可用來尋找符合條件的元素 print(x) #(array([1, 3, 5, 7]),)
利用searchsorted()可以回傳某個值應該要放在該陣列的第幾個才能符合已排序的陣列
默認值是從左側搜尋,加入side=’right’ 可以從右側搜尋
也可以放入多個值,只要以逗號分隔即可
arr = np.array([6, 7, 8, 9]) x = np.searchsorted(arr, 10) #想在陣列中放入10 print(x) #4,索引值為4才可以保持陣列的順序
篩選陣列
輸入True或False可以從原有的陣列中取得元素來建立新陣列
arr = np.array([41, 42, 43, 44]) x = [True, False, True, False] newarr = arr[x] print(newarr) #[41, 43]
假如陣列的元素數量多的時候,可以用for迴圈來寫篩選條件
arr = np.array([41, 42, 43, 44]) filter_arr = [ ] #建立空的陣列 for element in arr: if element > 42: filter_arr.append(True) else: filter_arr.append(False) newarr = arr[filter_arr] print(filter_arr) #[False, False, True, True] print(newarr) #[43 44]
好的,Ep. 9的整理就到這裡了,還有很多是和統計學有關的應用,就不在這裡贅述了。另外,我想你們也會對Python的資料分析套件Pandas感到興趣,來看看吧!
Python初學總整理 全系列:
Python初學總整理 第3講:Python資料型態和運算子
Python初學總整理 第4講:Python條件、迴圈與函數
Python初學總整理 第7講:爬蟲實例解析 – 以爬取臉書社團為案例,使用 Selenium 來進行網頁模擬爬蟲
Python初學總整理 第9講:Numpy函式庫 (本篇)
文章看完還是不知道該從哪裡下手?
就從線上課程開始吧!不讓你獨自摸索好幾個月,用8小時帶你走完基礎與精華,培養你基礎的Python概念,讓自學下一步不是煩惱!
全新Python 課程上架,8小時基礎實戰!,限時優惠只要NT 600 (HDK 120 起)!
不讓妳浪費一整天,只要你8小時,就能讓你學會基礎!
如果你的入門還在單打獨鬥,歡迎來到快樂學程式找到志同道合的夥伴,你的自學之路不孤單。
參考資料
- https://www.w3schools.com/python/numpy_intro.asp
- https://zh.wikipedia.org/wiki/NumPy
- https://blog.techbridge.cc/2020/08/24/numpy-zen-intro-tutorial/