[Python] Numpy 學習筆記: ufunc[np-003]
本篇文章將介紹我在學習Numpy應用的筆記學。
內容架構結合了w3school以及我在工研院上AI課程的筆記,以下皆有透過colab連結,以.ipynb檔讀取,可以登入Google帳戶查看。架構如:
二、ufunc
是numpy中的通用函數,包含了基本的運算邏輯,是實際上在計算資料時,非常重要的一個部份,特別是當我們想要用手刻方式來建立模型,那麼,資料的運算過程就變得非常重要。
全名 “Universal Functions” ,用來處理 “ndarray”物件。
在進入運算之前,網路上也有許多關於為什麼要使用numpy的討論,所有的答案的指引到了效率問題。在numpy有很特別的設計,讓array都是以向量化來進行加減乘除,大大降低了透過迴圈或其他方式的運算時間。
什麼是向量化 (Vectorization)?
以vec(A)的m × n矩陣A的向量化來說,
是通過將矩陣A的各列彼此堆疊而獲得的mn ×1列向量。
但光說不練,實在難信服。我們就用範例一決勝負吧。
給定一個 1,000,000 筆A資料集合,以及1,000,000 筆B資料集合,求每一對 ai 和 bi 相乘的結果的總和c?
每次起步都一樣,我們先引入套件,但在這裡為了計算運算效率,我們需要time這個套件,幫我們算出終點時間點減去起始時間點=耗費時間。
import numpy as np
import time as t
生成資料集合。
a = np.random.rand(1000000)
b = np.random.rand(1000000)
c = 0
方法一:用傳統的for迴圈逐一運算。
StartTime = t.time()for i in range(100000):
c += a[i]*b[i]DeltaTime = t.time() — StartTime
print(‘結果=’+str(c)+’耗時:’+str(1000*DeltaTime)+’ ms’)
結果=24958.2096,耗時:62.1336 ms
方法二:用numpy進行運算。
StartTime = t.time()c = np.dot(a, b)DeltaTime = t.time() — StartTime
print(‘結果=’+str(c)+’耗時:’+str(1000*DeltaTime)+’ ms’)
結果=24958.2096,耗時:1.5506 ms
勝負很明顯了,numpy大大超越了for迴圈的運算效率。且我們在此還只是一維的運算,若拓展到高維度,或是資料筆數再向上延伸,都會再將差距大幅拉開。
numpy也有廣播broadcasting或是reduce與accumulate等聰明的運算方式。
廣播功能將會視維度由左至右拓展,若數值符合對應,或數值為1時,皆可以進行運算。
當運算兩個array時, NumPy會根據 shapes進行 element-wise。
It starts with the trailing (i.e. rightmost) dimensions and works its way left.
a = np.array([1,2,3])
b_1 = np.array([2,2,2])
b_2 = 2print(a * b_1) #[2 4 6]
print(a * b_2) #[2 4 6]
官方網站也提出更多的範例:
四則運算
arr1 = np.array([10, 11, 12, 13, 14, 15])
arr2 = np.array([20, 21, 22, 23, 24, 25])np.add(arr1, arr2) #[30 32 34 36 38 40]
np.subtract(arr1, arr2) #[-10 -10 -10 -10 -10 -10]
np.multiply(arr1, arr2) #[200 231 264 299 336 375]
np.divide(arr1, arr2) #[0.5 0.5952 0.5455 0.5617 0.5833 0.6]
對比過去我們逐一運算,需要採用zip的方式,numpy提供的向量/矩陣運算是更加便捷的。
x = [1,2,3,4]
y = [4,5,6,7]
z = []#方法一 採用zip
for i, j in zip(x,y):
z.append(i+j)
print(z) #[5, 7, 9, 11]#方法二 採用numpy
z = np.add(x,y)
print(z) #[ 5 7 9 11]
同時也有其他的運算方式,譬如:
- power 次方運算
arr1 = np.array([2, 2, 2, 2, 2])
arr2 = np.array([2, 3, 4, 5, 6])np.power(arr1, arr2) #[ 4 8 16 32 64]
- mod 計算餘數
arr1 = np.array([10, 20, 30, 40, 50, 60])
arr2 = np.array([3, 7, 9, 8, 2, 33])np.mod(arr1, arr2) #[ 1 6 3 0 0 27]
- divmod 同時印出商數和餘數 (Quotient and Mod)
arr1 = np.array([10, 20, 30, 40, 50, 60])
arr2 = np.array([3, 7, 9, 8, 2, 33])np.divmod(arr1, arr2)
#(array([ 3, 2, 3, 5, 25, 1]), array([ 1, 6, 3, 0, 0, 27]))
小數位處理
np.fix([-3.1666, 3.6667]) #[-3. 3.] 捨去小數位,功能同trunc()
np.around([-3.1666, 3.6667], 2)#[-3.17 3.67] 設定位數四捨五入
np.floor([-3.1666, 3.6667]) #[-4. 3.] 無條件捨去
np.ceil([-3.1666, 3.6667]) #[-3. 4.] 無條件進位