NumPy 提供了兩種基本的對象,即 ndarray 和 ufunc 對象。ufunc 是 universal function的縮寫,意思是“通用函數(shù)”,它是一種能對數(shù)組的每個元素進行操作的函數(shù)。
許多 ufunc 函數(shù)都是用C語言級別實現(xiàn)的,因此它們的計算速度非???。
此外,ufun 比 math 模塊中的函數(shù)更靈活。math 模塊的輸入一般是標(biāo)量,但 NumPy 中的函數(shù)可以是向量或矩陣,而利用向量或矩陣可以避免使用循環(huán)語句,這點在機器學(xué)習(xí)、深度學(xué)習(xí)中非常重要。
ufunc 用于在 NumPy 中實現(xiàn)矢量化,這比迭代元素要快得多。
它們還提供廣播和其他方法,例如減少、累加等,它們對計算非常有幫助。
ufuncs 還接受其他參數(shù),比如:
where 布爾值數(shù)組或條件,用于定義應(yīng)在何處進行操作。
dtype 定義元素的返回類型。
out 返回值應(yīng)被復(fù)制到的輸出數(shù)組。
函數(shù) | 使用方法 |
sqrt() | 計算序列化數(shù)據(jù)的平方根 |
sin()、cos() | 三角函數(shù) |
abs() | 計算序列化數(shù)據(jù)的絕對值 |
dot() | 矩陣運算 |
log()、logl()、log2() | 對數(shù)函數(shù) |
exp() | 指數(shù)函數(shù) |
cumsum()、cumproduct() | 累計求和、求積 |
sum() | 對一個序列化數(shù)據(jù)進行求和 |
mean() | 計算均值 |
median() | 計算中位數(shù) |
std() | 計算標(biāo)準(zhǔn)差 |
var() | 計算方差 |
corrcoef() | 計算相關(guān)系數(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 )
運行結(jié)果:
math.sin: 0.5169950000000005 numpy.sin: 0.05381199999999886
由此可見,numpy.sin 比 math.sin 快近 10 倍。
將迭代語句轉(zhuǎn)換為基于向量的操作稱為向量化。
由于現(xiàn)代 CPU 已針對此類操作進行了優(yōu)化,因此速度更快。
對兩個列表的元素進行相加:
list 1: [1, 2, 3, 4]
list 2: [4, 5, 6, 7]
一種方法是遍歷兩個列表,然后對每個元素求和。
如果沒有 ufunc,我們可以使用 Python 的內(nèi)置 zip() 方法:
x = [1, 2, 3, 4] y = [4, 5, 6, 7] z = [] for i, j in zip(x, y): z.append(i + j) print(z)
運行結(jié)果:
[5, 7, 9, 11]
對此,NumPy 有一個 ufunc,名為 add(x, y),它會輸出相同的結(jié)果,通過 ufunc,我們可以使用 add() 函數(shù):
import numpy as np x = [1, 2, 3, 4] y = [4, 5, 6, 7] z = np.add(x, y) print(z)
運行結(jié)果:
[5, 7, 9, 11]
充分使用 Python 的 NumPy 庫中的內(nèi)建函數(shù)(Built-in Function),來實現(xiàn)計算的向量化,可大大地提高運行速度。NumPy 庫中的內(nèi)建函數(shù)使用了 SIMD 指令。如下使用的向量化要比使用循環(huán)計算速度快得多。如果使用 GPU,其性能將更強大,不過 Numpy 不支持 GPU。
請看下面的代碼:
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循環(huán)-----計算時間 = " + 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 版本---- 計算時間 = " + str(1000*(toc - tic)) + "ms")
運行結(jié)果:
dot = 250215.601995 for循環(huán)-----計算時間 = 798.3389819999998ms dot = 250215.601995 Verctor 版本---- 計算時間 = 1.885051999999554ms