1. 程式人生 > >使用NumPy陣列進行面向陣列程式設計

使用NumPy陣列進行面向陣列程式設計

1使用陣列進行面向陣列程式設計

使用NumPy陣列可以使你利用簡單的陣列表示式完成多種資料操作任務,而無須寫些大量迴圈。這種利用陣列表示式來替代顯示迴圈的方法,稱為向量化。
假設我們想要對一些網格資料來計算函式sqrt(x ^ 2 + y ^ 2)的值。np.meshgrid函式接收兩個一維陣列,並根據兩個陣列的所有(x,y)對生成一個二維矩陣:

import numpy as np
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]]

接下來使用matplotlib來生成這個二維陣列的視覺化:

plt.imshow(z,cmap = plt.cm.gray)
plt.colorbar()
plt.title("Image plot of $sqrt{x^2+y^2}$ for a grid of values")
plt.show()

生成的影象如圖:
在這裡插入圖片描述

1.1將條件邏輯作為陣列操作

np.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時,我們取xarr中的對應元素,否則取yarr中的元素。
使用np.where可以非常簡單地完成:

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 = np.where(cond,xarr,yarr)
print(result)
---------------------------------------------
[1.1 2.2 1.3 1.4 2.5]

np.where的第二個引數和第三個引數並不需要是陣列,它們可以是標量。where在資料分析中的一個典型用法是根據一個數組來生成另一個新的陣列:

arr = np.random.randn(4,4)
print(arr)
--------------------------------------------------
[[ 1.21632914 -1.50662094  0.62310929  0.2784616 ]
 [ 1.55591903  1.12405435  1.01905272 -0.35865934]
 [-0.1620057  -1.46639065  0.63714704  0.94117963]
 [-0.67466668 -0.18557065 -0.19931116  0.02813137]]
print(np.where(arr > 0,2,-2))
--------------------------------------------------
[[ 2 -2  2  2]
 [ 2  2  2 -2]
 [-2 -2  2  2]
 [-2 -2 -2  2]]

上述這段程式碼表示將隨機生成的矩陣資料中的正值都替換為2,其餘的值替換為-2。
使用下面這段程式碼僅將正值設為2:

np.where(arr > 0,2,arr)

傳遞給np.where的陣列既可以是同等大小的陣列,也可以是標量。

1.2數學和統計方法

許多關於計算整個陣列統計值或關於軸向資料的數學函式,可以作為陣列型別的方法被呼叫。我們可以使用聚合函式(縮排函式),比如sum、mean、std(標準差),既可以直接呼叫陣列例項的方法,也可以使用頂層的NumPy函式。
我們可以生成一些正態分佈的隨機數,並且計算部分聚合統計資料:

arr = np.random.randn(5,4)
print(arr)
print(arr.mean()) #求矩陣中所有資料的平均數
print(np.mean(arr)) #求矩陣中所有資料的平均數
print(arr.sum()) #求矩陣中所有資料的和

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

print(arr.mean(axis = 1)) #計算每一列的平均值
print(arr.sum(axis = 0)) #計算每一行的和

例如cumcum和cumprod等函式並不會聚合,它們會產生一箇中間結果:

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

在多維陣列中,可以在指定軸向上根據較低維度的切片進行部分聚合:

arr = np.array([[0,1,2],[3,4,5],[6,7,8]])
print(arr)
-----------------------------------------
[[0 1 2]
 [3 4 5]
 [6 7 8]]
print(arr.cumsum(axis = 0))
-----------------------------------------
[[ 0  1  2]
 [ 3  5  7]
 [ 9 12 15]]
print(arr.cumprod(axis = 1))
-----------------------------------------
[[  0   0   0]
 [  3  12  60]
 [  6  42 336]]

表1-1:基礎陣列統計方法

方法 描述
mean 數學平均,0長度的陣列平均值為NaN
std,var 標準差和方差,可以選擇自由度調整(預設分母是n)
argmin,argmax 最小值和最大值的位置
cumsum 從0開始的累積和
cumprod 從0開始的累積積

1.3布林值陣列的方法

sum函式也可以用於計算布林值陣列中的True的個數:

arr = np.random.randn(100)
print((arr > 0).sum()) #47

對於布林值陣列,有兩個方法any和all。any檢查陣列中是否至少有一個True,而all檢查是否每個值都是True:

bools = np.array([False,False,True,False])
print(bools.any()) #True
print(bools.all()) #False

這些方法也可適用於非布林值陣列,所有非0元素都會按True處理。

1.4排序

NumPy陣列也可以使用sort方法按位置排序:

arr = np.random.randn(6)
print(arr)
-------------------------------------------------------------------------
[ 0.53632097  0.29496073  1.1998889   2.30062577 -0.04549287  0.76208047]
arr.sort()
print(arr)
-------------------------------------------------------------------------
[-0.04549287  0.29496073  0.53632097  0.76208047  1.1998889   2.30062577]

我們也可以在多維陣列中根據傳遞的axis的值,沿著軸向對每個一維資料段進行排序:

arr = np.random.randn(5,3)
print(arr)
--------------------------------------
[[-0.33661808  0.89571615 -1.42058487]
 [-0.76615842 -1.13877178 -1.04613436]
 [-0.18069874 -1.18844477  1.21160409]
 [-1.16649883  2.54782531 -1.18748065]
 [-0.57765213  1.16266895 -0.55191486]]
arr.sort(1)
print(arr)
--------------------------------------
[[-1.42058487 -0.33661808  0.89571615]
 [-1.13877178 -1.04613436 -0.76615842]
 [-1.18844477 -0.18069874  1.21160409]
 [-1.18748065 -1.16649883  2.54782531]
 [-0.57765213 -0.55191486  1.16266895]]

1.5唯一值與其他集合邏輯

np.unique方法返回的是陣列中唯一值排序後形成的陣列:

names = np.array(['Bob','Joe','Will','Bob','Will','Joe','Joe'])
print(np.unique(names)) #['Bob' 'Joe' 'Will']

純python是這樣來實現的:

print(sorted(set(names))) #['Bob', 'Joe', 'Will']

另一個函式,np.in1d,可以檢查一個數組中的值是否在另一個數組中,並返回一個布林值陣列:

values = np.array([6,0,0,3,2,5,6])
print(np.in1d(values,[2,3,6])) #[ True False False  True  True False  True]