1、通用函數
NumPy提供了一個簡單靈活的接口來優化數據數組的計算。使NumPy變快的關鍵是利用向量化操作,通常在NumPy的通用函數中實現。可以通過簡單對數組執行操作來實現,這裏對數組的操作會被用於數組中的每一個元素,這種向量方法被用於將循環推送至NumPy之下的 編譯層,這樣會取得更快的執行效率。
NumPy實現的算術運算符
運算符 | 對應的通用函數 | 描述 |
+ | np.add | 加法運算(即1+1=2) |
- | np.subtract | 減法運算(即3-2=1) |
- | np.negative | 負數運算(即-2) |
* | np.multiply | 乘法運算(即2* 3= 6) |
/ | np.divide | 除法運算(即3/2=1.5) |
// | np.floor_divide | 地板除法運算(floor division,即3//2=1) |
** | np.power | 指數運算(即2**3=8) |
% | np.mod | 模/餘數(即9%4=1) |
對於非常小的輸入值可以保持較好的精度,當x的值很小時,以上函數給出的值比np.log和np.exp的計算更精確
print("exp(x) - 1 = ",np.expm1(x))
exp(x) - 1 = [0. 0.0010005 0.01005017 0.10517092]
print("log(1+x)=",np.log1p(x))
log(1+x)= [0. 0.0009995 0.00995033 0.09531018]
NumPy一元函數
對ndarray中的數據執行元素級運算的函數
函數 | 說明 |
np.abs(x) np.fabs(x) | 計算數組各元素的絕對值(計算整數、浮點數或複數的絕對值,對於非複數,可以使用更快的fabs) |
np.sqrt(x) | 計算數組各元素的平方根,相當於arr**0.5 |
np.square(x) | 計算數組各元素的平方,相當於arr**2 |
np.log(x) np.log10(x) np.log2(x) |
計算數組各元素的自然對數(e)、10底對數和2底對數 |
np.ceil(x) np.floor(x) | 計算數組各元素的ceiling值(表示不超過元素的整數值)或floor值(小於這個元素的最大整數值) |
np.rint(x) |
計算數組各元素的四捨五入值,保留dtype |
np.modf(x) | 將數組各元素的小數和整數部分以兩個獨立數組形式返回 |
np.cos(x) np.cosh(x) np.sin(x) np.sinh(x) np.tan(x) np.tanh(x) |
計算數組各元素的普通型和雙曲型三角函數 |
np.exp(x) | 計算數組各元素的指數值 e^x |
np.exp2(x) | 2^x |
np.power(3,x) | 3^x |
np.sign(x) | 計算數組各元素的符號值(正負號):1(+),0,-1(-) |
isnan | 返回一個表示“哪些值是NAN(這不是一個數字)”的布爾型數組 |
isfinite、isinf | 分別返回一個表示“哪些元素是有窮的(非inf,非NaN)”或“哪些元素是無窮的”的布爾型數組 |
arccos、arccosh、arcsin、 arcsinh、arctan、arctanh、 logical_not |
反三角函數、 計算各元素not x的真值,相當於-arr |
a = np.arange(24).reshape((2,3,4))
np.square(a) #數組本身並未發生改變,新生成了結果
Out[31]:
array([[[ 0, 1, 4, 9],
[ 16, 25, 36, 49],
[ 64, 81, 100, 121]],
[[144, 169, 196, 225],
[256, 289, 324, 361],
[400, 441, 484, 529]]], dtype=int32)
a = np.sqrt(a)
a
Out[33]:
array([[[0. , 1. , 1.41421356, 1.73205081],
[2. , 2.23606798, 2.44948974, 2.64575131],
[2.82842712, 3. , 3.16227766, 3.31662479]],
[[3.46410162, 3.60555128, 3.74165739, 3.87298335],
[4. , 4.12310563, 4.24264069, 4.35889894],
[4.47213595, 4.58257569, 4.69041576, 4.79583152]]])
np.modf(a)
Out[34]:
(array([[[0. , 0. , 0.41421356, 0.73205081],
[0. , 0.23606798, 0.44948974, 0.64575131],
[0.82842712, 0. , 0.16227766, 0.31662479]],
[[0.46410162, 0.60555128, 0.74165739, 0.87298335],
[0. , 0.12310563, 0.24264069, 0.35889894],
[0.47213595, 0.58257569, 0.69041576, 0.79583152]]]),
array([[[0., 1., 1., 1.],
[2., 2., 2., 2.],
[2., 3., 3., 3.]],
[[3., 3., 3., 3.],
[4., 4., 4., 4.],
[4., 4., 4., 4.]]]))
a = np.arange(24).reshape((2,3,4))
b = np.sqrt(a)
a
Out[38]:
array([[[ 0, 1, 2, 3],
[ 4, 5, 6, 7],
[ 8, 9, 10, 11]],
[[12, 13, 14, 15],
[16, 17, 18, 19],
[20, 21, 22, 23]]])
b
Out[39]:
array([[[0. , 1. , 1.41421356, 1.73205081],
[2. , 2.23606798, 2.44948974, 2.64575131],
[2.82842712, 3. , 3.16227766, 3.31662479]],
[[3.46410162, 3.60555128, 3.74165739, 3.87298335],
[4. , 4.12310563, 4.24264069, 4.35889894],
[4.47213595, 4.58257569, 4.69041576, 4.79583152]]])
np.maximum(a,b)
Out[40]: #生成結果爲浮點數類型
array([[[ 0., 1., 2., 3.],
[ 4., 5., 6., 7.],
[ 8., 9., 10., 11.]],
[[12., 13., 14., 15.],
[16., 17., 18., 19.],
[20., 21., 22., 23.]]])
a>b
Out[41]:
array([[[False, False, True, True],
[ True, True, True, True],
[ True, True, True, True]],
[[ True, True, True, True],
[ True, True, True, True],
[ True, True, True, True]]])
NumPy二元函數
函數 | 說明 |
+ - * / ** | 兩個數組各元素進行對應運算 |
np.maximum(x,y) np.fmax() np.minimum(x,y) np.fmin() |
元素級的最大值/最小值計算 |
np.mod(x,y) | 元素級的模運算 |
np.copysign(x,y) | 將數組y中各元素值得符號賦值給數組x對應元素 |
> >= < <= == != (greater、greater_equal、less、less_equal、equal、not_equal) |
算術比較,產生布爾型數組(執行元素級的比較運算,最終產生布爾型數組。相當於中綴運算符) |
maximum、fmax | 元素級的最大值計算,fmax將忽略NaN |
minimum、fmin | 元素級的最小值計算,fmin將忽略NaN |
logical_and、logical_or、logical_xor | 執行元素級的真值邏輯運算,相當於中綴運算符&、|、^ |
專用的通用函數
子模塊scipy.special。scipy.special可能包含了你需要的計算函數,這些函數能列一個長長的列表
from scipy import special
#Gamma函數(廣義階乘,generalized factorials)和相關函數
x = [1,5,10]
print("gamma(x) = ",special.gamma(x))
gamma(x) = [1.0000e+00 2.4000e+01 3.6288e+05]
print("ln|gamma(x)| = ",special.gammaln(x))
ln|gamma(x)| = [ 0. 3.17805383 12.80182748]
print("beta(x,2) = ",special.beta(x,2))
beta(x,2) = [0.5 0.03333333 0.00909091]
#誤差函數(高斯積分),它的實現和它的逆實現
x = np.array([0,0.3,0.7,1.0])
print("erf(x) = ",special.erf(x))
erf(x) = [0. 0.32862676 0.67780119 0.84270079]
print("erfc(x) = ",special.erfc(x))
erfc(x) = [1. 0.67137324 0.32219881 0.15729921]
print("erfinv(x) = ",special.erfinv(x))
erfinv(x) = [0. 0.27246271 0.73286908 inf]
更多通用函數,搜索gamma function python
2、利用數組進行數據處理
NumPy數組可以將多種數據處理任務表述爲簡潔的數組表達式。用數組表達式代替循環的做法,通常稱爲矢量化。一般來說,矢量化數組運算比等價的純Python方式快上一兩個數量級(甚至更多),尤其是各種數值計算。
假設我們想要一組值(網格型)上計算函數sqrt(x^2+y^2)。np.meshgrid函數接受兩個一維數組,併產生兩個二維矩陣(對應於兩個數組中的所有的(x,y)對):
points = np.arange(-5,5,0.01) #1000個間隔相等的點
xs,ys = np.meshgrid(points,points) #meshgrid函數將xs,ys中的一個隨機轉置
xs
Out[19]:
array([[-5. , -4.99, -4.98, ..., 4.97, 4.98, 4.99],
[-5. , -4.99, -4.98, ..., 4.97, 4.98, 4.99],
[-5. , -4.99, -4.98, ..., 4.97, 4.98, 4.99],
...,
[-5. , -4.99, -4.98, ..., 4.97, 4.98, 4.99],
[-5. , -4.99, -4.98, ..., 4.97, 4.98, 4.99],
[-5. , -4.99, -4.98, ..., 4.97, 4.98, 4.99]])
z = np.sqrt(xs**2+ys**2)
print(z)
[[7.07106781 7.06400028 7.05693985 ... 7.04988652 7.05693985 7.06400028]
[7.06400028 7.05692568 7.04985815 ... 7.04279774 7.04985815 7.05692568]
[7.05693985 7.04985815 7.04278354 ... 7.03571603 7.04278354 7.04985815]
...
[7.04988652 7.04279774 7.03571603 ... 7.0286414 7.03571603 7.04279774]
[7.05693985 7.04985815 7.04278354 ... 7.03571603 7.04278354 7.04985815]
[7.06400028 7.05692568 7.04985815 ... 7.04279774 7.04985815 7.0569256
3、將條件邏輯表述爲數組運算
numpy.where函數是三元表達式 x if condition else y的矢量化版本,假設我們有一個布爾數組和兩個值數組:
xarr = np.array([1.1,1.2,1.3,1.4,1.5])
yarr = np.array([2.1,2.2,2.3,2.4,2.5])
cond = np.array([True,False,True,False,True])
result = [(x if c else y) for x,y,c in zip(xarr,yarr,cond)]
print(result)
[1.1, 2.2, 1.3, 2.4, 1.5]
有幾個問題,第一,它對於大數組的處理速度不是很快(因爲所有工作都是純Python完成的),第二,無法用於多維數組,若使用np.where,則可以將該功能寫得非常簡潔:
result = np.where(cond,xarr,yarr)
print(result)
[1.1 2.2 1.3 2.4 1.5]
np.where的第二個和第三個參數不必是數組,它們都可以是標量值。在數據分析工作中,where通常用於根據另一個數組而產生一個新的數組。假設有一個由隨機數據組成的矩陣,希望將所有正值替換爲2,將所有負值替換爲-2.若利用np.where,則會非常簡單。
arr = np.random.randn(4,4)
arr
Out[34]:
array([[ 0.38784541, -0.76510336, -0.82989414, -1.02121355],
[-1.08224846, 0.57193671, 1.704616 , -1.51224614],
[-0.23296425, -0.74999226, -0.25997311, 0.02762807],
[-1.40279474, -0.85967699, 0.43397061, 0.21096187]])
np.where(arr>0,2,2)
Out[35]:
array([[2, 2, 2, 2],
[2, 2, 2, 2],
[2, 2, 2, 2],
[2, 2, 2, 2]])
4、數學和統計方法
可以通過數組上的一組數學函數對整個數組或某個軸向的數據進行統計計算。sum、mean以及標準差std等聚合計算(aggregation,通常叫做約簡(reduction))既可以當做數組的實例方法調用,也可以當做頂級NumPy函數使用:
arr = np.random.randn(5,4) #正態分佈的數據
arr.mean()
Out[37]: -0.05251800712883138
np.mean(arr)
Out[38]: -0.05251800712883138
arr.sum()
Out[39]: -1.0503601425766276
mean和sum這類的函數可以接受一個axis參數(用於計算該軸向上的統計值),最終結果是一個少一維的數組:
arr.mean(axis = 1)
Out[40]: array([ 0.15764388, 0.01108259, -0.47893468, -0.34661133, 0.39422951])
arr.sum(0)
Out[41]: array([-0.61037358, 0.39095319, 0.89721238, -1.72815214])
其他如cumsum和cumprod之類的方法則不聚合,而是產生一個由中間結果組成的數組:
arr = np.array([[0,1,2],[3,4,5],[6,7,8]])
arr.cumsum(0)
Out[44]:
array([[ 0, 1, 2],
[ 3, 5, 7],
[ 9, 12, 15]], dtype=int32)
arr.cumprod(1)
Out[45]:
array([[ 0, 0, 0],
[ 3, 12, 60],
[ 6, 42, 336]], dtype=int32)
sum | 對數組中全部或某軸向的元素求和,零長度的數組sum爲0 |
mean | 算術平均數。零長度的數組的mean爲NaN |
std、var | 分別爲標準差和方差,自由度可調(默認爲n) |
min、max | 最大值和最小值 |
argmin、argmax | 分別爲最大和最小元素的索引 |
cumsum | 所有元素的累計和 |
cumprod | 所有元素的累計積 |
5、用於布爾型數組的方法
上面方法中,布爾值會被強制轉換爲1(True)和0(False)。因此,sum經常被用來對布爾型數組中的True值計數:
arr = np.random.randn(100)
(arr>0).sum() #正值的數量
Out[48]: 49
另外還有兩個方法any和all,他們對布爾型數組非常有用,any用於測試數組中是否存在一個或多個True,而all則檢查數組中所有值是否都是True:
bools = np.array([False,False,True,False])
bools.any()
Out[50]: True
bools.all()
Out[51]: False
這兩個方法也能用於非布爾型數組,所有非0元素將會被當做True。
6、排序
跟Python內置的列表類型一樣,NumPy數組也可以通過sort方法就地排序:
arr = np.random.randn(8)
arr
Out[54]:
array([ 0.70217459, -0.06398129, -0.43286682, -1.52234138, -1.97647823,
-0.31417911, -0.68201874, 1.65370152])
arr.sort()
arr
Out[56]:
array([-1.97647823, -1.52234138, -0.68201874, -0.43286682, -0.31417911,
-0.06398129, 0.70217459, 1.65370152])
多維數組可以在任何一個軸向上進行排序,只需將軸編號傳給sort即可:
arr = np.random.randn(5,3)
arr
Out[60]:
array([[ 0.42509416, 0.38131833, 0.52802406],
[-0.25573096, 0.87563357, 0.35797497],
[-0.42483493, 0.96273352, 0.46142089],
[ 1.88208657, -0.41488597, -1.29519319],
[ 1.09697647, -1.01891748, -0.09269173]])
arr.sort(1)
arr
Out[62]:
array([[ 0.38131833, 0.42509416, 0.52802406],
[-0.25573096, 0.35797497, 0.87563357],
[-0.42483493, 0.46142089, 0.96273352],
[-1.29519319, -0.41488597, 1.88208657],
[-1.01891748, -0.09269173, 1.09697647]])
頂級方法np.sort返回的是數組的已排序副本,而就地排序則會修改數組本身。計算數組分位數最簡單的辦法是對其進行排序,然後選取特定位置的值:
arr = np.random.randn(5,3)
arr
Out[60]:
array([[ 0.42509416, 0.38131833, 0.52802406],
[-0.25573096, 0.87563357, 0.35797497],
[-0.42483493, 0.96273352, 0.46142089],
[ 1.88208657, -0.41488597, -1.29519319],
[ 1.09697647, -1.01891748, -0.09269173]])
arr.sort(1)
arr
Out[62]:
array([[ 0.38131833, 0.42509416, 0.52802406],
[-0.25573096, 0.35797497, 0.87563357],
[-0.42483493, 0.46142089, 0.96273352],
[-1.29519319, -0.41488597, 1.88208657],
[-1.01891748, -0.09269173, 1.09697647]])
7、唯一化以及其他的集合邏輯
NumPy提供了一些針對一維ndarray的基本集合運算,最常用的可能要數np.uniqrw,它用於找出數組中的唯一值並返回已排序的結果:
names = np.array(['Bob','Joe','Will','Bob','Will','Joe','Joe'])
np.unique(names)
Out[70]: array(['Bob', 'Joe', 'Will'], dtype='<U4')
等價python代碼:
sorted(set(names))
Out[71]: ['Bob', 'Joe', 'Will']
另一個函數np.in1d用於測試一個數組中的值在另一個數組中的成員資格,返回一個布爾型數組:
unique(x) | 計算x中的唯一元素,並返回有序元素 |
intersect1d(x,y) | 計算x和y的公共元素,並返回有序結果 |
union1d(x,y) | 計算x和y的並集,並返回有序結果 |
int1d(x,y) | 得到一個表示“x的元素是否包含於y”的布爾型數組 |
setdiff1d(x,y) | 集合的差,即元素在x中且不在y中 |
setxor1d(x,y) | 集合的對稱差,即存在於一個數組中但不同時存在於兩個數組中的元素(異或) |
8、高級的通用函數特性
(1)指定輸出
不同於創建臨時數組,有時候可以指定一個用於存放運算結果的數組,將計算結果直接寫入到期望的存儲位置。所有通用函數都可以通過out參數來指定計算結果的存放位置:
x = np.arange(5)
y = np.empty(5)
np.multiply(x,10,out=y)
Out[27]: array([ 0., 10., 20., 30., 40.])
print(y)
[ 0. 10. 20. 30. 40.]
這個特性也可以被用作數組視圖,例如可以將計算結果寫入指定數組的每隔一個元素的位置:
y = np.zeros(10)
np.power(2,x,out=y[::2])
Out[31]: array([ 1., 2., 4., 8., 16.])
如果是y[::2] = 2 ** x,那麼結果將是創建一個臨時數組,該數組存放的是2**x的結果,並且接下來會將這些值複製到y數組中。對於上述例子中比較小的計算量來說,這兩種方式的差別並不大。但是對於較大的數組,通過慎重使用out參數將能夠有效節約內存。
(2)聚合
二元二元通用函數有些非常有趣的聚合功能, 這些聚合可以直接在對象上計算。
例如, 如果我們希望用一個特定的運算 reduce 一個數組, 那麼可以用任何通用函數的 reduce 方法。 一個 reduce 方法會對給定的元素和操作重複執行, 直至得到單個的結果。
①對 add 通用函數調用 reduce 方法會返回數組中所有元素的和:
x = np.arange(1,6)
np.add.reduce(x)
Out[36]: 15
②對multiply通用函數調用reduce方法會返回數組中所有元素的乘積:
np.multiply.reduce(x)
Out[37]: 120
如果需要存儲每次計算的中間結果,可以使用accumulate
np.add.accumulate(x)
Out[38]: array([ 1, 3, 6, 10, 15], dtype=int32)
np.multiply.accumulate(x)
Out[39]: array([ 1, 2, 6, 24, 120], dtype=int32)
③外積
任何通用函數都可以用outer方法獲得兩個不同輸入數組所有元素對的函數運算結果。
任何通用函數都可以用outer方法獲得兩個不同輸入數組所有元素對的函數運算結果。這意味着你可以用一行代碼實現一個乘法表:
x = np.arange(1,10) #打印了一個九九乘法表
np.multiply.outer(x,x)
Out[41]:
array([[ 1, 2, 3, 4, 5, 6, 7, 8, 9],
[ 2, 4, 6, 8, 10, 12, 14, 16, 18],
[ 3, 6, 9, 12, 15, 18, 21, 24, 27],
[ 4, 8, 12, 16, 20, 24, 28, 32, 36],
[ 5, 10, 15, 20, 25, 30, 35, 40, 45],
[ 6, 12, 18, 24, 30, 36, 42, 48, 54],
[ 7, 14, 21, 28, 35, 42, 49, 56, 63],
[ 8, 16, 24, 32, 40, 48, 56, 64, 72],
[ 9, 18, 27, 36, 45, 54, 63, 72, 81]])
有關通用函數的更多信息(包括可用的通用函數的完整列表) 可以在NumPy(http://www.numpy.org) 和 SciPy(http://www.scipy.org) 文檔的網站找到。