fbpx

嗨,大家好,我是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初學總整理 第1講:Python簡介

Python初學總整理 第2講:Python開發環境

Python初學總整理 第3講:Python資料型態和運算子

Python初學總整理 第4講:Python條件、迴圈與函數

Python初學總整理 第5講:爬蟲應用(上)

Python初學總整理 第6講:爬蟲應用(下)

Python初學總整理 第7講:爬蟲實例解析 – 以爬取臉書社團為案例,使用 Selenium 來進行網頁模擬爬蟲

Python初學總整理 第8講:Matplotlib套件

Python初學總整理 第9講:Numpy函式庫 (本篇)

 

 

 


文章看完還是不知道該從哪裡下手?

就從線上課程開始吧!不讓你獨自摸索好幾個月,用8小時帶你走完基礎與精華,培養你基礎的Python概念,讓自學下一步不是煩惱!

 全新Python 課程上架,8小時基礎實戰!,限時優惠只要NT 600 (HDK 120 起)!

不讓妳浪費一整天,只要你8小時,就能讓你學會基礎!

如果你的入門還在單打獨鬥,歡迎來到快樂學程式找到志同道合的夥伴,你的自學之路不孤單。

參考資料

  1. https://www.w3schools.com/python/numpy_intro.asp
  2. https://zh.wikipedia.org/wiki/NumPy
  3. https://blog.techbridge.cc/2020/08/24/numpy-zen-intro-tutorial/

Leave a Reply