机器学习中的Numpy库基础——向量、矩阵和数组
1.Numpy簡介
Numpy是Python機(jī)器學(xué)習(xí)技術(shù)棧的基礎(chǔ)。
Numpy可以對機(jī)器學(xué)習(xí)中常用的數(shù)據(jù)結(jié)構(gòu)——向量(vector)、矩陣(matrice)、張量(tensor)——進(jìn)行高效的操作。
Numpy是很多庫的基礎(chǔ),比如Scipy、Matplotlib、OpenCV、scikit-learn等,非常重要。
之前寫過一篇博文,對其中的操作進(jìn)行了梳理 → Here
本文對其中的內(nèi)容進(jìn)行整理和補(bǔ)充,希望能更好地指引初學(xué)者的腳步。
2.創(chuàng)建一個(gè)向量
向量可以表示為一維數(shù)組。
# 加載numpy庫 import numpy as np# 創(chuàng)建一個(gè)一維數(shù)組表示一個(gè)行向量 vector_row = np.array([1, 2, 3])# 創(chuàng)建一個(gè)一維數(shù)組表示一個(gè)列向量 vector_column = np.array([[1], [2], [3]])3.創(chuàng)建一個(gè)矩陣
矩陣可以表示為一個(gè)二維數(shù)組。
表示的時(shí)候注意[[, ], [, ], [, ]]這樣的格式,不要漏外括號。
當(dāng)然,在Numpy中,可以用專門的矩陣數(shù)據(jù)結(jié)構(gòu)來表示矩陣。
但并不推薦——Reasons:
- 數(shù)組才是Numpy標(biāo)準(zhǔn)的數(shù)據(jù)結(jié)構(gòu)。
- 絕大多數(shù)Numpy操作返回的是數(shù)組而不是矩陣對象。
4.創(chuàng)建一個(gè)稀疏矩陣
我們在學(xué)習(xí)數(shù)據(jù)結(jié)構(gòu)時(shí)學(xué)習(xí)了稀疏矩陣的知識。
機(jī)器學(xué)習(xí)中,數(shù)據(jù)集十分龐大且其中大部分元素是0的情況很常見,如果正常存儲十分浪費(fèi)空間;但按照稀疏矩陣存儲,能節(jié)省空間、降低計(jì)算成本。
總結(jié):稀疏矩陣能高效地表示只有零星非零值的數(shù)據(jù)。
我們可以查看稀疏矩陣:
# 查看稀疏矩陣 print(matrix2_sparse)我們再看一看更大的矩陣吧:
# 創(chuàng)建一個(gè)更大的矩陣 matrix_large = np.array([[0, 0, 0, 0, 0, 0, 0, 0, 0, 0],[0, 1, 0, 0, 0, 0, 0, 0, 0, 0],[3, 0, 0, 0, 0, 0, 0, 0, 0, 0]])# 創(chuàng)建一個(gè)CSR矩陣 matrix_large_sparse = sparse.csr_matrix(matrix_large)# 查看原先的稀疏矩陣 print(matrix2_sparse)# 查看更大的稀疏矩陣 print(matrix_large_sparse)稀疏矩陣的類型很多,比如,壓縮的稀疏列、表中表以及鍵值對字典,我們應(yīng)該學(xué)會在合適的場景運(yùn)用合適的類型。
5.選擇元素
我們可以利用索引,在向量或矩陣中選擇一個(gè)或多個(gè)元素。
注意索引都是從0開始的呀!
另外,負(fù)數(shù)索引是倒著來的,這點(diǎn)也要注意哈!
眾所周知,Python的列表和元組就有索引和切片,那么這里其實(shí)也有的:
# 選取一個(gè)向量的所有元素 print(vector[:])# 選取從0開始一直到第3個(gè)(包含第3個(gè))元素 print(vector[:3])# 選取第3個(gè)元素之后的全部元素 print(vector[3:])# 選取最后一個(gè)元素 print(vector[-1])# 選取矩陣的第1行和第2行以及所有列 print(matrix_vector[:2, :])# 選取所有行以及第2列 print(matrix_vector[:, 1:2])# 選取所有行以及第2列并轉(zhuǎn)換成一個(gè)新的行向量 print(matrix_vector[:, 1])6.展示一個(gè)矩陣的屬性
有時(shí)候,在某一步操作之前,我們可能想確認(rèn)一下矩陣的形狀、大小和維數(shù),這可能是簡單的,也可能很重要。
接下來我們分別利用shape查看矩陣的形狀、利用size查看矩陣的大小、利用ndim查看矩陣的維數(shù):
7.對多個(gè)元素同時(shí)應(yīng)用某個(gè)操作
我們有時(shí)候可能想要對一個(gè)數(shù)組中的多個(gè)元素同時(shí)應(yīng)用某個(gè)函數(shù),而Numpy中的vertorize類可以將一個(gè)函數(shù)轉(zhuǎn)成另一個(gè)函數(shù),這個(gè)函數(shù)能把某個(gè)操作應(yīng)用的數(shù)組的全部元素或者一個(gè)切片上。
需要明確的是,vertorize本質(zhì)上是在對數(shù)組選中的所有元素循環(huán)的執(zhí)行某種操作,所以并不會提升性能。
此外,使用Numpy的數(shù)組,我們可以對兩個(gè)維度不同的數(shù)組執(zhí)行操作(這是一種叫做廣播的方法):
matrix_vector + 1008.找到最大值和最小值
計(jì)算一個(gè)數(shù)組的最大值或者最小值可能是重要的。
# 加載numpy庫 import numpy as np# 創(chuàng)建矩陣 matrix_vector = np.array([[1, 2, 3], [4, 5, 6], [7, 8, 9]])# 返回最大的元素 print(np.max(matrix_vector))# 返回最小元素 print(np.min(matrix_vector))如上所述,求一個(gè)數(shù)組或者一個(gè)數(shù)組的子集中元素的最大值和最小值是很常見的需求,使用max和min方法易于實(shí)現(xiàn)。而使用axis參數(shù)可以對一個(gè)特定的坐標(biāo)軸應(yīng)用此操作:
# 找到每一列的最大元素 print(np.max(matrix_vector, axis=0))# 找到每一行最大的元素 print(np.max(matrix_vector, axis=1))9.計(jì)算平均值、方差和標(biāo)準(zhǔn)差
如果我們還記得學(xué)過的概率論與數(shù)理統(tǒng)計(jì)的內(nèi)容的話,就會知道一些重要的描述性統(tǒng)計(jì)值,如數(shù)學(xué)期望、方差和標(biāo)準(zhǔn)差等,這里我們可以利用Numpy的mean、var和std求解:
# 加載numpy庫 import numpy as np# 創(chuàng)建矩陣 matrix_vector = np.array([[1, 2, 3], [4, 5, 6], [7, 8, 9]])# 返回平均值 print(np.mean(matrix_vector))# 返回方差 print(np.var(matrix_vector))# 返回標(biāo)準(zhǔn)差 print(np.std(matrix_vector))我們當(dāng)然可以容易的求出整個(gè)矩陣或者其中一個(gè)坐標(biāo)軸的描述性統(tǒng)計(jì)值:
# 求每一列的平均值 print(np.mean(matrix_vector, axis=0))# 求每一行的方差 print(np.var(matrix_vector, axis=1))10.矩陣變形
有時(shí)候,我們可能會想在不改變元素值的前提下,改變一個(gè)數(shù)組的形狀(行數(shù)和列數(shù)),Numpy的reshape可以實(shí)現(xiàn)這種要求。
reshape可以重構(gòu)一個(gè)數(shù)組,維持該數(shù)組原來的數(shù)據(jù)不變,只改變行數(shù)和列數(shù)。但要求原矩陣和新矩陣包含的元素個(gè)數(shù)必須相同(大小相同)。比如,2 × 6 矩陣可以換成 3 × 4 矩陣,元素個(gè)數(shù)都是12個(gè)。
reshape能傳入?yún)?shù)-1,這時(shí)意味著可以“根據(jù)需要填充元素”。
# reshape時(shí)傳入?yún)?shù)-1意味著可以根據(jù)需要填充元素 print(matrix3.reshape(1, -1))只提供一個(gè)整數(shù)作為參數(shù)也是可以的,會返回一個(gè)長度為該整數(shù)的一維數(shù)組:
# reshape如果提供一個(gè)整數(shù),那么reshape會返回一個(gè)長度為該整數(shù)值的一維數(shù)組 print(matrix3.reshape(12))11.轉(zhuǎn)置向量或矩陣
學(xué)過線性代數(shù)之后我們都知道,轉(zhuǎn)置是常見的操作,它將矩陣的每個(gè)元素的行坐標(biāo)、列坐標(biāo)互換。
# 加載numpy庫 import numpy as np# 創(chuàng)建矩陣 matrix_vector = np.array([[1, 2, 3], [4, 5, 6], [7, 8, 9]])# 轉(zhuǎn)置matrix_vector矩陣 print(matrix_vector.T)實(shí)際上,在線性代數(shù)里面,向量是不能被轉(zhuǎn)置的。
我們?nèi)绻搿稗D(zhuǎn)置向量”,就需要把向量純粹的當(dāng)做1×N或者N×1的矩陣處理(即用[[, ]]而不是[, ]):
12.展開一個(gè)矩陣
所謂“展開”矩陣,不過是將一個(gè)矩陣轉(zhuǎn)換成一個(gè)一維數(shù)組,Numpy中的flatten可以幫助我們實(shí)現(xiàn):
# 加載numpy庫 import numpy as np# 創(chuàng)建矩陣 matrix_vector = np.array([[1, 2, 3], [4, 5, 6], [7, 8, 9]])# 將matrix_vector矩陣展開 print(matrix_vector.flatten())我們才看過的reshape顯然也能完成這種小任務(wù):
# 將矩陣展開的另一種策略是利用reshape創(chuàng)建一個(gè)行向量 print(matrix_vector.reshape(1, -1))13.計(jì)算矩陣的秩
線性代數(shù)里面,矩陣的秩也是重要的概念。為了便于理解,我們這里就不提什么向量組的極大無關(guān)組那些,我們可以認(rèn)為矩陣的秩就是按照其行或者列展開的向量空間的維數(shù),神圣的Numpy提供了matrix_rank,我們利用它可以輕松求解:
# 加載numpy庫 import numpy as np# 創(chuàng)建用于求秩的新矩陣 matrix5 = np.array([[1, 1, 1], [1, 1, 10], [1, 1, 15]])# 計(jì)算矩陣matrix5的秩 print(np.linalg.matrix_rank(matrix5))14.計(jì)算行列式
我在學(xué)線性代數(shù)的時(shí)候,行列式是最早學(xué)的Part了,行列式只是一個(gè)數(shù)而已,但矩陣的行列式是很有用的。
簡而言之,矩陣的[ ]換成| |就是矩陣的行列式的表示(手寫版),只是從一個(gè)數(shù)表變成了一個(gè)數(shù)。
求解行列式可能是復(fù)雜的,但Numpy的det幫助我們解決了這個(gè)問題:
15.獲取矩陣的對角線元素
有時(shí)候,我們可能想要獲取矩陣的對角線元素,Numpy的diagonal能幫到我們:
# 加載numpy庫 import numpy as np# 創(chuàng)建用于行列式求解的新矩陣 matrix6 = np.array([[1, 2, 3], [2, 4, 6], [3, 8, 9]])# 返回矩陣的對角線元素 print(matrix6.diagonal())我們還可以使用offset參數(shù)在主對角線上下偏移,獲取偏移后的對角線方向上的元素:
# 返回主對角線向上偏移量為1的對角線元素 print(matrix6.diagonal(offset=1))# 返回主對角線向下偏移量為1的對角線元素 print(matrix6.diagonal(offset=-1))16.計(jì)算矩陣的跡
線性代數(shù)里提到了矩陣的跡,指矩陣對角線元素之和,常被用在機(jī)器學(xué)習(xí)方法的底層計(jì)算中,Numpy的trace可以加以求解:
# 加載numpy庫 import numpy as np# 創(chuàng)建用于行列式求解的新矩陣 matrix6 = np.array([[1, 2, 3], [2, 4, 6], [3, 8, 9]])# 返回矩陣的跡 print(matrix6.trace())當(dāng)然,也可以麻煩一些,利用對矩陣對角線元素求和的方式求解:
# 求跡的另外的方法(返回對角線元素并求和) print(sum(matrix6.diagonal()))17.計(jì)算特征值和特征向量
線性代數(shù)中,矩陣的特征值和特征向量特別重要,我學(xué)習(xí)的時(shí)候這是矩陣相似對角化的重要基礎(chǔ)。另外,假設(shè)線性變換是以矩陣A的形式給出的,則當(dāng)應(yīng)用此線性變換的時(shí)候,特征向量只會改變大小(不改變方向)。
Aν = λν(A為方陣,λ是特征值,ν是特征向量)
Numpy的eig可以幫助我們求解(想我當(dāng)年學(xué)線代,這倆東西算起來也是頗為麻煩的):
18.計(jì)算點(diǎn)積
向量的點(diǎn)積其實(shí)在高中就學(xué)習(xí)了,在線性代數(shù)和空間解析幾何中也是重要內(nèi)容。可以這樣定義:
Numpy的dot可以完成這個(gè)任務(wù):
Python 3.5+版本可以利用@求解向量點(diǎn)積:
# Python 3.5+ 版本可以這樣求解點(diǎn)積 print(vector_a @ vector_b)19.計(jì)算矩陣的相加或相減
所謂矩陣加法或者減法,無非是在兩個(gè)形狀大小完全一致的矩陣上,對每個(gè)元素逐一進(jìn)行加減法,Numpy的add和subtract可以分別實(shí)現(xiàn)矩陣加減法:
# 加載numpy庫 import numpy as np# 構(gòu)造兩個(gè)可用于加減的矩陣 matrix_a = np.array([[1, 1, 1], [1, 1, 1], [1, 1, 2]]) matrix_b = np.array([[1, 3, 1], [1, 3, 1], [1, 3, 8]])# 兩矩陣相加 print(np.add(matrix_a, matrix_b))# 兩矩陣相減 print(np.subtract(matrix_a, matrix_b))直接利用運(yùn)算符運(yùn)算也是被支持的:
# 直接用+/-也可以做矩陣加減 print(matrix_a + matrix_b) print(matrix_a - matrix_b)20.矩陣的乘法
矩陣乘法的實(shí)現(xiàn)類似向量乘法,可以用Numpy的dot:
# 加載numpy庫 import numpy as np# 構(gòu)造兩個(gè)可用于乘法的小矩陣 matrix_c = np.array([[1, 1], [1, 2]]) matrix_d = np.array([[1, 3], [1, 2]])# 兩矩陣相乘 print(np.dot(matrix_c, matrix_d))Python 3.5+版本可以利用@求解矩陣乘法:
# Python 3.5+ 版本可以這樣求解矩陣乘法 print(matrix_c @ matrix_d)只是把矩陣對應(yīng)元素相乘,可以用*求解:
# 我們也可以把兩矩陣對應(yīng)元素相乘,而非矩陣乘法 print(matrix_c * matrix_d)21.計(jì)算矩陣的逆
如果逆矩陣存在,則可以用Numpy的linalg.inv來計(jì)算:
# 加載numpy庫 import numpy as np# 創(chuàng)建一個(gè)用于求逆的矩陣 matrix8 = np.array([[1, 4], [2, 5]])# 計(jì)算矩陣的逆 print(np.linalg.inv(matrix8))如果逆矩陣存在,矩陣本身和逆矩陣相乘得到單位矩陣:
# 驗(yàn)證一個(gè)矩陣和它的逆矩陣相乘等于I(單位矩陣) print(matrix8 @ np.linalg.inv(matrix8))22.生成隨機(jī)數(shù)
偽隨機(jī)數(shù)是很重要的,值得一提的是,其生成器中有“種子”。
# 加載numpy庫 import numpy as np# 設(shè)置隨機(jī)數(shù)種子 np.random.seed(0)# 生成3個(gè)0.0~1.0之間的浮點(diǎn)隨機(jī)數(shù) print(np.random.random(3))我們繼續(xù)看看吧:
# 生成3個(gè)1~10之間的隨機(jī)整數(shù) print(np.random.randint(0, 11, 3))# 從平均值是0.0,標(biāo)準(zhǔn)差是1.0的正態(tài)分布中抽取3個(gè)數(shù) print(np.random.normal(0.0, 1.0, 3))# 從平均值是0.0,散布程度是1.0的logistic分布中抽取3個(gè)數(shù) print(np.random.logistic(0.0, 1.0, 3))# 從大于等于1.0,小于2.0的范圍內(nèi)抽取3個(gè)數(shù) print(np.random.uniform(1.0, 2.0, 3))總結(jié)
Numpy有豐富的內(nèi)容,本文舉一些經(jīng)典的應(yīng)用加以闡釋,還望對讀者有所幫助。
總結(jié)
以上是生活随笔為你收集整理的机器学习中的Numpy库基础——向量、矩阵和数组的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 【面向对象】面向对象程序设计测试题7-对
- 下一篇: 【计算机科学基础】ASCII码表知识总结