Python之Numpy庫(7)

補充內容

來自《利用Python進行數據分析》,僅供自己學習使用,嚴禁轉載用於其他商業用途。

神奇的索引

arr = np.empty((8, 4))
for i in range(8):
    arr[i] = i
print(arr)
print('------------')
print(arr[[4, 3, 0, 6]])
print('------------')
print(arr[[-3, -5, -7]])

#結果
[[0. 0. 0. 0.]
 [1. 1. 1. 1.]
 [2. 2. 2. 2.]
 [3. 3. 3. 3.]
 [4. 4. 4. 4.]
 [5. 5. 5. 5.]
 [6. 6. 6. 6.]
 [7. 7. 7. 7.]]
------------
[[4. 4. 4. 4.]
 [3. 3. 3. 3.]
 [0. 0. 0. 0.]
 [6. 6. 6. 6.]]
------------
[[5. 5. 5. 5.]
 [3. 3. 3. 3.]
 [1. 1. 1. 1.]]

 首先,我們生成一個8行4列的數組,然後根據索引進行切片,取出第4,3,0,6四行的數據,最後,我們根據索引,取出倒數第3、5、7行的數據。

傳遞多個索引數組時情況有些許不同,這樣會根據每個索引元組對應的元素選出一個一維數組:

arr = np.arange(32).reshape((8, 4))
print(arr)

#結果
[[ 0  1  2  3]
 [ 4  5  6  7]
 [ 8  9 10 11]
 [12 13 14 15]
 [16 17 18 19]
 [20 21 22 23]
 [24 25 26 27]
 [28 29 30 31]]
print(arr[[1,5,7,2],[0,3,1,2]])

#
[ 4 23 29 10]

上述例子中,元素(1,0)、(5,3)、(7,1)、(2,2)被選中。如果不考慮數組的維數,索引的結果總是一維的。

數組轉置和換軸

轉置是一種特殊的數據重組形式,可以返回底層數據的視圖而不需要賦值任何內容。數組擁有transpose方法,也有特殊的T屬性。

import numpy as np
arr = np.arange(15).reshape((3, 5))
print(arr)
print('--------------')
print(arr.T)

#
[[ 0  1  2  3  4]
 [ 5  6  7  8  9]
 [10 11 12 13 14]]
--------------
[[ 0  5 10]
 [ 1  6 11]
 [ 2  7 12]
 [ 3  8 13]
 [ 4  9 14]]

可以發現,原數組的行和列進行了互換。

當進行矩陣操作時,有事還會用到一些特定操作。如計算矩陣內積會使用np.dot

arr = np.random.randn(6, 3)
print(arr)
print('--------')
print(np.dot(arr.T, arr))

#
[[ 2.36529252  1.45634028 -0.45027236]
 [-1.85345472  1.50493214 -0.13627173]
 [-1.05013824 -0.13728287 -0.24801649]
 [-0.85897001  0.14457997  1.79092397]
 [ 1.24476335 -1.34613385 -0.23993914]
 [-0.77263369  0.04402339 -0.49494594]]
--------
[[13.0169215  -1.03430871 -2.00660628]
 [-1.03430871  6.23951211 -0.26664834]
 [-2.00660628 -0.26664834  3.79277832]]

對於更高維度的數組,transpose方法可以接受包含軸編號的元組,用於置換軸:

arr = np.arange(16).reshape((2, 2, 4))
print(arr)
print('--------')
print(arr.transpose((1, 0, 2)))

#
[[[ 0  1  2  3]
  [ 4  5  6  7]]

 [[ 8  9 10 11]
  [12 13 14 15]]]
--------
[[[ 0  1  2  3]
  [ 8  9 10 11]]

 [[ 4  5  6  7]
  [12 13 14 15]]]

這裏,軸已經被重新排序,使得原先的第二個軸變爲第一個,原先的第一個軸變成第二個,最後一個軸並沒有變。

通用函數:快速的逐元素數組函數

通用函數,也可以成爲ufunc,是一種在ndarray數據中進行逐元素操作的函數。某些簡單函數接受一個或多個標量數值,併產生一個或多個標量結果,而通用函數就是對這些簡單函數的向量化封裝。

arr = np.arange(10)
print(arr)
print('----------')
print(np.sqrt(arr))
print('----------')
print(np.exp(arr))

#
[0 1 2 3 4 5 6 7 8 9]
----------
[0.         1.         1.41421356 1.73205081 2.         2.23606798
 2.44948974 2.64575131 2.82842712 3.        ]
----------
[1.00000000e+00 2.71828183e+00 7.38905610e+00 2.00855369e+01
 5.45981500e+01 1.48413159e+02 4.03428793e+02 1.09663316e+03
 2.98095799e+03 8.10308393e+03]

使用sqrt()方法對數組內的元素開根號,exp()方法返回e的n次方,e是一個常數爲2.71828。

這是所謂的一元通用函數,還有一些通用函數,比如add或maximum則會接受兩個數組並返回一個數組作爲結果,因此成爲二元通用函數:

x = np.random.randn(8)
y = np.random.randn(8)
print(x)
print(y)
print(np.maximum(x, y))

#
[-2.01960726  0.51696239  0.77124305  1.20857829 -1.204375    1.4427587
  0.12709071  0.29780411]
[-0.28531979 -0.32238757 -0.44377128 -0.3816275   1.75887677  0.98860426
 -0.76177926 -0.84858413]
[-0.28531979  0.51696239  0.77124305  1.20857829  1.75887677  1.4427587
  0.12709071  0.29780411]

numpy.maximum逐個元素地將x和y中元素最大的值計算出來。

也有一些返回多個數組的函數。比如modf,是python內建函數divmod的向量化版本,它返回一個浮點值數組的小數部分和整數部分:

arr = np.random.randn(7) * 5
print(arr)
remainder, whole_part = np.modf(arr)
print(remainder)
print(whole_part)

#
[ 8.11757348 -0.70141921 -0.41606526  0.55060716  6.30934265 -5.97310928
  3.95041647]
[ 0.11757348 -0.70141921 -0.41606526  0.55060716  0.30934265 -0.97310928
  0.95041647]
[ 8. -0. -0.  0.  6. -5.  3.]

賦值時,前面的是小數部分,後面的是整數部分。

表1 一元通用函數
函數名 描述
abs、fabs 逐元素地計算整數、浮點數或複數的絕對值
sqrt 計算每個元素的平方根(與arr ** 0.5相等)
square 計算每個元素的平方(與arr**2相等)
exp 計算每個元素的自然指數值e**x
log、log10、log2、log1p 分別對應:自然對數(e爲底)、對數10爲底、對數2爲底、log(1+x)
sign 計算每個元素的符號值:1(正數)、0(0)、-1(負數)
ceil 計算每個元素的最高整數值(即大於等於給定數值的最小整數)
floor 計算每個元素的最小整數值(即小於等於給定數值的最大整數)
modf 分別將數組中的小數部分和整數部分按數組形式返回
isnan 返回數組中的元素是否是一個NaN(不是一個數值),形式爲布爾值數組
isfinite、isinf 分別返回數組中的元素是否有限(非inf、非NaN)、是否無限的,形式爲布爾值數組
cos、cosh、sin、sinh、tan、tanh 常規的三角函數

arccos、arccosh、arcsin、

arcsinh、arctan、arctanh

反三角函數
logical_not 對數組的元素按位取反(與~arr效果一樣)

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

表2 二元通用函數
函數名 描述
add 將數組的對應元素增加
subtract 在第二個數組中,將第一個數組中包含的元組去除
multiply 將數組的對應元素相乘
divide, floor_divide 除或整除(放棄餘數)
power 將第二個數組的元素作爲第一個數組對應元素的冪次方
maximum, fmax 逐個元素計算最大值,fmax忽略NaN
minimum, fmin 逐個元素計算最小值,fmax忽略NaN
mod 按元素的求模計算(即求除法的餘數)
copysign 將第一個數組的符號值改爲第二個數組的符號值

greater, greater_equal, less, 

less_equal, equal, not_equal, 

logical_and, logical_or, 

logical_xor

進行逐個元素的比較,返回布爾值數組(與數學操作符>、>=、<、<=、==、!= 效果一致)進行逐個元素的邏輯操作(與邏輯操作符&、|、^ 效果一致)

 

 

 

 

 

 

 

 

 

 

 

 

 

使用數組進行面向數組編程

利用數組表達式來替代顯示循環的方法,稱爲向量化。

points = np.arange(-5, 5, 0.01)
xs, ys = np.meshgrid(points, points)
print(ys)

#
[[-5.   -5.   -5.   ... -5.   -5.   -5.  ]
 [-4.99 -4.99 -4.99 ... -4.99 -4.99 -4.99]
 [-4.98 -4.98 -4.98 ... -4.98 -4.98 -4.98]
 ...
 [ 4.97  4.97  4.97 ...  4.97  4.97  4.97]
 [ 4.98  4.98  4.98 ...  4.98  4.98  4.98]
 [ 4.99  4.99  4.99 ...  4.99  4.99  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.05692568]]

可以求出根號下x**2 + y**2的值。

將條件邏輯作爲數組操作

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, True, False])
result = [(x if c else y) for x, y, c in zip(xarr, yarr, cond)]
print(result)

#
[1.1, 2.2, 1.3, 1.4, 2.5]

假設cond中的元素爲True時,我們取axrr中的對應元素值,否則取yarr中的元素值,可以通過以上代碼完成。但如果數組很大,速度會很慢,而使用np.where時,就可以非常簡單地完成:

result = np.where(cond, xarr, yarr)
print(result)

#
[1.1 2.2 1.3 1.4 2.5]

np.where的第二個和第三個參數並不需要是數組,它們可以是標量。

arr = np.random.randn(4, 4)
print(arr)
print(arr > 0)
print(np.where(arr > 0, 2, -2))

#
[[ 0.61766413  0.05565645  0.17577733 -0.37404451]
 [-0.13572482 -0.86114914 -0.07353302 -0.03741651]
 [-0.27460935  0.41297701  0.27868873 -0.63462777]
 [ 0.18022908 -0.54048348  0.43320103  0.31274484]]

[[ True  True  True False]
 [False False False False]
 [False  True  True False]
 [ True False  True  True]]

[[ 2  2  2 -2]
 [-2 -2 -2 -2]
 [-2  2  2 -2]
 [ 2 -2  2  2]]

例子中可以看到,我們將其中的正值都替換成2,負值都替換爲-2,使用np.where很容易實現。

如果僅將正值替換爲2,可以寫成:print(np.where(arr > 0, 2,arr))

數學和統計方法

arr = np.random.randn(5, 4)
print(arr)
print(arr.mean())
print(np.mean(arr))
print(arr.sum())

#
[[-2.80990453e-01 -7.58276181e-01 -1.14295903e+00 -1.38200808e+00]
 [-1.99594965e-01 -1.38398991e+00 -1.19742730e+00 -3.04548718e-01]
 [-2.27579601e-03 -1.31106338e-01  9.01807874e-01  5.98710554e-01]
 [ 2.30283103e+00  2.25508761e+00 -2.11443469e-01  1.31561031e+00]
 [ 1.34378629e+00  7.02711284e-01  1.58238066e+00  9.33821461e-01]]

0.24710634198581216

0.24710634198581216

4.942126839716243

像mean、sum等函數可以接受一個可選參數axis,這個參數可以用於計算給定軸向上的統計值,形成一個下降一維度的數組:

arr = np.random.randn(5, 4)
print(arr)
print(arr.mean(axis=1))
print(arr.sum(axis=0))

#
[[ 0.59696253  1.11121983 -0.1610959  -1.8332755 ]
 [ 0.07409587 -2.14484861  0.50016975  0.76153254]
 [-1.28510856  0.28761388  0.55825006  0.64558745]
 [-0.38153078  0.83174068 -0.92845526  0.1239845 ]
 [ 0.22249535 -0.68529482 -0.17869785 -0.7053025 ]]

[-0.07154726 -0.20226261  0.05158571 -0.08856521 -0.33669996]

[-0.77308559 -0.59956904 -0.20982921 -1.00747352]

arr.mean(1)表示“計算每一行的平均值”,而arr.sum(0)表示“計算列軸向的累和”。

其他的方法,例如cumsum和cumprod並不會聚合,它們會產生一箇中間結果:

arr = np.array([0, 1, 2, 3, 4, 5, 6, 7])
print(arr.cumsum())

#
[ 0  1  3  6 10 15 21 28]

在多維數組中,像cumsum這樣的累積函數返回相同長度的數組,但是可以在指定軸向上根據較低維度的切片進行部分聚合:

arr = np.array([[0, 1, 2], [3, 4, 5], [6, 7, 8]])
print(arr)
print(arr.cumsum(axis=0))
print(arr.cumprod(axis=1))

#
[[0 1 2]
 [3 4 5]
 [6 7 8]]

[[ 0  1  2]
 [ 3  5  7]
 [ 9 12 15]]

[[  0   0   0]
 [  3  12  60]
 [  6  42 336]]
表格3 基礎數組統計方法
方法 描述
sum 沿着軸向計算所有元素的累和,0長度的數組,累和爲0
mean 數學平均,0長度的數組平均值爲NaN
std, var 標準差和方差,可以選擇自由度調整(默認分母是n)
min, max  最大值和最小值
argmin, argmax 最大值和最小值的位置
cumsum 從0開始元素累積和
cumprod 從1開始元素累積積

 

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章