python資料分析之Numpy資料庫第三期陣列的運算

WorkerForrest發表於2020-11-28

上期陣列的索引和切片的知識總結通道:陣列的索引和切片

陣列和標量間的運算

陣列之所以強大而且重要的原因,是其不需要通過迴圈就可以完成批量計算,也就是向量化

import numpy as np
a = [1,2,3]
b=[]
for i in a:
    b.append(i*10)
b

out[1]:

[10, 20, 30]
arr = np.array([1,2,3])
arr *10

out[2]:

array([10, 20, 30])

相同維度的陣列的算術運算都可以直接應用到元素中,也就是元素級運算

arr*arr

out[3]:

array([1, 4, 9])
arr - arr

out[4];

array([0, 0, 0])

通用函式

通用函式(ufunc)是一種對陣列中的資料執行元素級運算的函式。例如:通過abs函式求絕對值,square函式求平方

arr = np.random.randn(3,3)
arr

out[5];

array([[-0.17634898,  1.24131891, -1.55449196],
       [ 0.04820966, -0.1420969 , -0.80747892],
       [-0.05187637,  0.41997844, -2.12123818]])
np.abs(arr)

out[6]:

array([[0.17634898, 1.24131891, 1.55449196],
       [0.04820966, 0.1420969 , 0.80747892],
       [0.05187637, 0.41997844, 2.12123818]])
np.square(arr)

out[7];

array([[3.10989635e-02, 1.54087265e+00, 2.41644525e+00],
       [2.32417090e-03, 2.01915297e-02, 6.52022212e-01],
       [2.69115814e-03, 1.76381893e-01, 4.49965142e+00]])

以上函式都是傳入一個陣列,所以這些函式都是一元函式。有些函式需要傳入倆個陣列並返回一個陣列,這些函式被稱為二元函式。例如:add函式用於倆個陣列相加,minimun函式可以計算元素最小值。

arr1 = np.random.randint(1,10,size = (5))
arr1

out[8]:

array([1, 8, 3, 2, 1])
arr2 = np.random.randint(1,10,size = (5))
arr2

out[9];

array([4, 8, 7, 4, 3])
np.add(arr1,arr2)

out[10]:

array([ 5, 16, 10,  6,  4])
np.minimum(arr1,arr2)

out[11]

array([1, 8, 3, 2, 1])

有些通用函式還可以返回倆個陣列,例如:modf函式,可以返回陣列元素的小數和整數部分

arr1 = np.random.normal(2,4,size=(6,))
arr

out[12]:

array([[-0.17634898,  1.24131891, -1.55449196],
       [ 0.04820966, -0.1420969 , -0.80747892],
       [-0.05187637,  0.41997844, -2.12123818]])
np.modf(arr)

out[13]:

(array([[-0.17634898,  0.24131891, -0.55449196],
        [ 0.04820966, -0.1420969 , -0.80747892],
        [-0.05187637,  0.41997844, -0.12123818]]),
 array([[-0.,  1., -1.],
        [ 0., -0., -0.],
        [-0.,  0., -2.]]))

條件邏輯運算

首先建立三個陣列

arr1 = np.array([1,2,3,4])
arr2 = np.array([5,6,7,8])
cond = np.array([True,False,False,True])

如果需要通過cond的值來選取arr1和arr2的值,當cond為True時,選擇arr1否則選擇arr2的值,那麼可以通過if語句判斷來實現。

result = [(x if c else y) for x,y,c in zip(arr1,arr2,cond)]
result

out[14];

[1, 6, 7, 4]

但這種方法存在倆個問題:第一,對大規模陣列處理速度不是很快;第二,無法用於多維陣列。若使用Numpy的where函式則可以解決這倆個問題

result = np.where(cond,arr1,arr2)
result

out[15]:

array([1, 6, 7, 4])

where函式中的第二個和第三個引數可以為標量。在資料分析,經常需要通過一些條件將陣列進行處理。例如新建一個隨機符合正態分佈的陣列,通過資料處理將正值替換為1,負值替換為-1.

arr = np.random.randn(4,4)
arr

out[16]:

array([[-0.47119857,  0.74300761, -2.02821269, -0.3549485 ],
       [ 1.36356163, -0.61257804,  0.48115343,  0.86997115],
       [-0.4559936 ,  0.26179048, -1.20468106, -0.56509321],
       [-0.23739251,  0.83751607, -0.33541895,  0.76305371]])
new_arr = np.where(arr>0,1,-1)
new_arr

out[17]

array([[-1,  1, -1, -1],
       [ 1, -1,  1,  1],
       [-1,  1, -1, -1],
       [-1,  1, -1,  1]])

使用elif函式可以進行多條件的判別。np.where函式通過巢狀的where表示式也可以完成同樣的功能

arr = np.random.randint(1,300,size=(3,3))
arr

out[18];

array([[203, 102, 270],
       [136,  60, 106],
       [126,  97,  64]])
new_arr = np.where(arr > 200,3,
                  np.where(arr>100,2,1))
new_arr

out[19]:

array([[3, 2, 3],
       [2, 1, 2],
       [2, 1, 1]])

統計運算

Numpy庫支援對整個陣列或按指定軸向的資料進行統計計算,例如,sum函式用於求和;mean函式用於求算術平均數;std函式用於求標準差。

arr = np.random.randn(4,4)
arr

out[20]

array([[ 0.30819793, -1.06144959,  1.46672816,  1.18847115],
       [ 0.87732943, -1.58171074, -0.6957929 ,  0.72827265],
       [ 0.31470934, -0.46280001, -0.40335385,  1.52528851],
       [ 2.28676812,  0.20790929, -0.11272405,  1.74249516]])
arr.sum()

out[21];

6.328338600041427
arr.mean()

out[22];

0.3955211625025892
arr.std()

out[23]

1.0515585180241533

上面這些函式也可以傳入axis引數,用於計算指定軸方向的統計值

arr.mean(axis=1)

out[24];

array([ 0.47548691, -0.16797539,  0.243461  ,  1.03111213])
arr.sum(0)

out[25]:

array([ 3.78700481, -2.89805105,  0.25485737,  5.18452746])

cumsum和cumpod方法會產生計算結果組成的陣列

arr = np.arange(9).reshape(3,3)
arr

out[26]:

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

out[27];

array([[ 0,  1,  2],
       [ 3,  5,  7],
       [ 9, 12, 15]], dtype=int32)
arr.cumprod(1)

out[28]

array([[  0,   0,   0],
       [  3,  12,  60],
       [  6,  42, 336]], dtype=int32)
#基本陣列的統計方法
#方法                   使用說明
#sum                    求和
#mean                   算術平均數
#std、var               標準差和方差
#min、max               最小值和最大值
#argmin、argmax         最小和最大元素的索引
#cumsum                 所有元素的累計和
#cumprod                所有元素的累計積

布林型陣列運算

對於布林型陣列,其布林值會被強制轉換為1(True)和0(False)

arr = np.random.randn(20)
arr

out[29]:

array([-0.42961012,  0.56609038, -1.1741952 , -0.75376119, -1.09201392,
        1.43960879,  0.87644242, -0.5947441 ,  1.08380455, -0.06300785,
        0.95369943, -1.27213285,  0.05017716,  0.27420381, -0.09095471,
       -1.35379462,  0.61902337, -0.59390741, -0.22647004, -0.03306254])
(arr > 0).sum()

out[30]:

8

另外還有倆種方法any和all也可以用於布林型陣列運算。any方法用於測試陣列中是否存在一個或多個True;all方法用於查詢陣列中的所有值是否為True

arr = np.array([True,False,False,True])
arr

out[31]:

array([ True, False, False,  True])
arr.any()

out[32];

True
arr.all()

out[33]:

False

排序

與python列表類似,Numpy陣列也可以通過sort()方法進行排序

arr = np.random.randn(10)
arr

out[34]:

array([ 2.2119974 , -1.52764083,  0.56082579,  0.14395966,  1.89882088,
        0.70710935, -1.89196899, -2.40109916,  1.64130244,  2.65960228])
arr.sort()
arr

out[35]:

array([-2.40109916, -1.89196899, -1.52764083,  0.14395966,  0.56082579,
        0.70710935,  1.64130244,  1.89882088,  2.2119974 ,  2.65960228])

對於多維陣列,可以通過指定軸方向進行排序

arr = np.random.randn(5,3)
arr

out[36]:

array([[ 2.45789818,  0.36223423, -0.77491822],
       [-0.90154818,  0.03508642,  0.59097629],
       [-1.11291537,  0.69388491, -0.53710136],
       [ 0.3184309 , -0.1081375 , -0.65716382],
       [-0.71120618,  1.60547342, -0.11556702]])
arr.sort(1)
arr

out[37]:

array([[-0.77491822,  0.36223423,  2.45789818],
       [-0.90154818,  0.03508642,  0.59097629],
       [-1.11291537, -0.53710136,  0.69388491],
       [-0.65716382, -0.1081375 ,  0.3184309 ],
       [-0.71120618, -0.11556702,  1.60547342]])

集合運算

Numpy庫中提供了針對一維陣列的基本集合運算。在資料分析中,常用np.unique方法找出陣列中的唯一值。

fruits = np.array(['apple','banana','pear','banana','pear','apple','pear'])
fruits

out[38]:

array(['apple', 'banana', 'pear', 'banana', 'pear', 'apple', 'pear'],
      dtype='<U6')
np.unique(fruits)

out[39]:

array(['apple', 'banana', 'pear'], dtype='<U6')
arr = np.array([2,3,3,2,8,1])
arr

out[40]:

array([2, 3, 3, 2, 8, 1])
np.unique(arr)

out[41]:

array([1, 2, 3, 8])

注意:唯一值進行了排序

np.in1d方法用於測試幾個陣列中是否包含相同的值,返回一個布林值陣列。

arr = np.array([2,3,5,7])
arr

out[42]:

array([2, 3, 5, 7])
np.in1d(arr,[2,7])

out[43]:

array([ True, False, False,  True])
#陣列的集合運算
#方法                                使用說明
#unique(x)                           唯一值
#intersect1d(x,y)                    公共元素
#union1d(x,y)                        並集
#in1d(x,y)                           x的元素是否在y中,返回布林型陣列
#setdiff1d(x,y)                      集合的差
#setxor1d(x,y)                       交集取反

線性代數

對於矩陣而言,需要求的是點積,這裡Numpy庫提供了用於矩陣乘法的dot函式

arr1 = np.array([[1,2,3],[4,5,6]])
arr1

out[44]:

array([[1, 2, 3],
       [4, 5, 6]])
arr2 = np.arange(9).reshape(3,3)
arr2

out[45]:

array([[0, 1, 2],
       [3, 4, 5],
       [6, 7, 8]])
np.dot(arr1,arr2)

out[46]:

array([[24, 30, 36],
       [51, 66, 81]])

對於更多的矩陣計算,可通過Numpy庫的linalg模組來完成

from numpy.linalg import det
arr = np.array([[1,2],[3,4]])
arr

out[47]:

array([[1, 2],
       [3, 4]])
det(arr)

out[48]:

-2.0000000000000004

注意:更多的矩陣運算說明可檢視linalg幫助

相關文章