? ? ? ? 好的,我們今天繼續(xù)來(lái)學(xué)習(xí)Numpy的基礎(chǔ),昨天,已經(jīng)介紹完Numpy的成員之一——數(shù)組,今天,在接著介紹其另一大成員——矩陣,也是應(yīng)用非常廣泛的成員。
? ? ? ? 矩陣,在線性代數(shù)中是幾乎貫穿全文的成員,因此,這里需要較高的線性代數(shù)的基礎(chǔ)。在這里,默認(rèn)對(duì)線性代數(shù)有全面的學(xué)習(xí)與認(rèn)識(shí),了解最基本的矩陣性質(zhì)及運(yùn)算。我們這里對(duì)于線性代數(shù)部分主要用于介紹,對(duì)變成部分新穎與重要部分進(jìn)行展示,便于以后的記憶。
? ? ? ? 因此,本章學(xué)習(xí)還是概念多余代碼,對(duì)于代碼,是比較簡(jiǎn)單的。
一、矩陣的基本屬性與計(jì)算
?1、數(shù)組的創(chuàng)建和轉(zhuǎn)置
? ? ? ? 對(duì)數(shù)組,創(chuàng)建也有特定的函數(shù),其函數(shù)為:matrix(),其可以將列表、元組、range對(duì)象等轉(zhuǎn)換為矩陣,其基礎(chǔ)的轉(zhuǎn)換舉例如下:
import numpy as np
# 創(chuàng)建基礎(chǔ)的矩陣
matr_base = np.matrix([[1, 2, 3], [4, 5, 6]])
matr_base_2 = np.matrix([1, 2, 3, 4, 5, 6])
# 逐層訪問(wèn)與單詞訪問(wèn)的區(qū)別
print(matr_base[1, 0])
print(matr_base[1][0])
? ? ? ? 其輸出的結(jié)果為:4和[[4 5 6]]。由此,我們可以推測(cè),對(duì)于矩陣一般只會(huì)存在單次訪問(wèn),如果是數(shù)組,此時(shí)兩者輸出的結(jié)果應(yīng)當(dāng)是相等的。對(duì)數(shù)組來(lái)說(shuō),其深入訪問(wèn)的方式為:先橫后縱的訪問(wèn)方式。
? ? ? ? 然而,對(duì)于矩陣來(lái)說(shuō),是不存在層層深入訪問(wèn)的,其所有的訪問(wèn)都是同類型的,都是訪問(wèn)的橫排,因此,深層訪問(wèn)基本不存在。
? ? ? ? 緊接著,是矩陣的轉(zhuǎn)置,對(duì)于矩陣的轉(zhuǎn)置,如同矩陣的轉(zhuǎn)置的寫(xiě)法一般,全文后面matr為矩陣舉例。因此,要將該矩陣轉(zhuǎn)置,只需要輸入matr.T即可得到轉(zhuǎn)置矩陣。矩陣的轉(zhuǎn)置無(wú)非是將每一橫行寫(xiě)成縱行,第二橫行改為第二縱行,由此,將局長(zhǎng)你轉(zhuǎn)置完成。
?2、矩陣的特征
? ? ? ? 在這里,列舉矩陣中numpy內(nèi)置的部分函數(shù),用于求矩陣的基本數(shù)。
# 所有元素的平均值
print(matr_base.mean())
# 縱向每列平均值
print(matr_base.mean(axis=0))
# 數(shù)組的形狀
print(matr_base.mean(axis=0).shape)
# 橫向每行平均值
print(matr_base.mean(axis=1))
# 所有元素之和
print(matr_base.sum())
# 橫向最大值
print(matr_base.max(axis=1))
# 橫向最大值的下標(biāo)
print(matr_base.argmax(axis=1))
# 對(duì)角線的元素
print(matr_base.diagonal())
# 非0元素的下標(biāo),分別返回行下標(biāo)和列下標(biāo)
print(matr_base.nonzero())
? ? ? ? 輸出的結(jié)果如下:
4
[[4 5 6]]
3.5
[[2.5 3.5 4.5]]
(1, 3)
[[2.]
[5.]]
21
[[3]
[6]]
[[2]
[2]]
[[1 5]]
(array([0, 0, 0, 1, 1, 1], dtype=int64), array([0, 1, 2, 0, 1, 2], dtype=int64))
?3、矩陣乘法
? ? ? ? 對(duì)矩陣乘法,一直有一個(gè)公式,那就是“左列=右行”方可進(jìn)行計(jì)算,計(jì)算出來(lái)的結(jié)果為“左行右列”。這是我現(xiàn)代自己便于記憶的公式。翻譯過(guò)來(lái)就是:左邊的列數(shù)必須與右邊的行數(shù)相等,乘出來(lái)的矩陣行數(shù)為左邊矩陣的行數(shù),列數(shù)為右邊矩陣的列數(shù)。
? ? ? ?非常值得注意的一點(diǎn)為:?矩陣的乘法不滿足交換律,交換之后可能無(wú)法相乘。
# 矩陣的乘法
matr_one=np.matrix([1,2,3]) ; matr_two=np.matrix(range(1,10))
matr_two.shape=3,3 ; matr_mult=matr_one*matr_two
print(matr_mult)
? ? ? ? 其輸出的結(jié)果為:[[30 36 42]]。
? ? ? ? 可以看到,1行3列矩陣與3行3列矩陣相乘,滿足上述兩個(gè)條件,得到的結(jié)果也如上。如果交換順序,便會(huì)產(chǎn)生錯(cuò)誤:
Traceback (most recent call last):
File "d:\PythonLearn\PythonWork\專題Numpy基礎(chǔ)(下)_矩陣.py", line 36, in <module>
print(matr_two*matr_one)
~~~~~~~~^~~~~~~~~
File "D:\Python312\Lib\site-packages\numpy\matrixlib\defmatrix.py", line 219, in __mul__
return N.dot(self, asmatrix(other))
^^^^^^^^^^^^^^^^^^^^^^^^^^^^
ValueError: shapes (3,3) and (1,3) not aligned: 3 (dim 1) != 1 (dim 0)
? ? ? ? 我們可以看到啊,它指出了3!=1,兩者不等,不能進(jìn)行相乘。
?4、相關(guān)系數(shù)矩陣與三差
? ? ? ? 對(duì)于相關(guān)系數(shù)矩陣,就是一個(gè)對(duì)稱陣(關(guān)于主對(duì)角線完全對(duì)稱),主對(duì)角線上的元素全都是1,副對(duì)角線上的元素表示對(duì)應(yīng)位置的相關(guān)系數(shù),每個(gè)元素的絕對(duì)值小于1。權(quán)威正則正相關(guān),相反則負(fù)相關(guān)。numpy中用corrcoef()函數(shù)計(jì)算相關(guān)矩陣。
# 計(jì)算相關(guān)矩陣
# 負(fù)相關(guān)矩陣
print(np.corrcoef([[1, 2, 3, 4], [4, 3, 2, 1]]))
print(np.corrcoef([[1, 2, 3, 4], [8, 3, 2, 1]]))
# 正相關(guān)矩陣
print(np.corrcoef([[1, 2, 3, 4], [1, 2, 3, 4]]))
print(np.corrcoef([[1, 2, 3, 4], [1, 2, 3, 40]]))
? ? ? ? 最終得到的結(jié)果如下:
[[ 1. -1.]
[-1. 1.]]
[[ 1. -0.91350028]
[-0.91350028 1. ]]
[[1. 1.]
[1. 1.]]
[[1. 0.8010362]
[0.8010362 1. ]]
? ? ? ? 下面,我們?cè)趯W(xué)習(xí)對(duì)三差的計(jì)算:方差、標(biāo)準(zhǔn)差、協(xié)方差。其中,標(biāo)準(zhǔn)差與協(xié)方差在概率論里面涉及較為多,前兩個(gè)的定義已經(jīng)耳熟能詳了,對(duì)于協(xié)方差,概率論的定義為:
期望值分別為E[X]與E[Y]的兩個(gè)實(shí)隨機(jī)變量X與Y之間的協(xié)方差Cov(X,Y)定義為:
? ? ? ? 實(shí)際協(xié)方差也為方差的特殊種類,這里只管應(yīng)用,在數(shù)學(xué)建模領(lǐng)域,這個(gè)是個(gè)重要的概念,大家是需要深入學(xué)習(xí)的。我們這里只學(xué)函數(shù)應(yīng)用。std()函數(shù)表示保準(zhǔn)差,cov表示方差,合理應(yīng)用就是協(xié)方差。以下有例子:
# 三差的計(jì)算
x = [-2.1, -1, 4.3] ; y = [3, 1.1, 0.12] ; matr_dif = np.vstack((x, y))
# 協(xié)方差
print(np.cov(matr_dif))
print(np.cov(x,y))
# 標(biāo)準(zhǔn)差
print(np.std(matr_dif))
print(np.std(matr_dif, axis=1))
# 方差
print(np.cov(x))
? ? ? ? 起計(jì)算原理是一個(gè)簡(jiǎn)單的數(shù)學(xué)問(wèn)題,直接看其運(yùn)行的結(jié)果為:
[[11.71 -4.286 ]
[-4.286 2.14413333]]
[[11.71 -4.286 ]
[-4.286 2.14413333]]
2.2071223094538484
[2.79404128 1.19558447]
11.709999999999999
? ? ? ?
?5、計(jì)算特征值與特征向量
? ? ? ? 首先我們需要知道特征值是針對(duì)方陣所特殊的存在,其線性代數(shù)的計(jì)算方法為,變形后得到,因此,需要用這個(gè)公式對(duì)原A方陣進(jìn)行變形,最后才能得到其一個(gè)或者多個(gè)特征根。
????????在numpy中,其子模塊linalg中,提供的特征值與特征向量為eig()函數(shù)。其函數(shù)的使用格式為:
# 特征值與特征向量
matr_esp = np.matrix([[2, -2, 0], [-2, 1, -2], [0, -2, 0]])
nmd_matr, st_matr = np.linalg.eig(matr_esp)
print(nmd_matr, st_matr, sep='\n')
print(type(nmd_matr), type(st_matr), sep='\n')
? ? ? ? 特征值,特征向量 = np.linalg.eig(matr),因此,基于此規(guī)則,對(duì)特征值的求法就是一個(gè)函數(shù),但這里需要注意的是,求矩陣的特征向量,建立時(shí)應(yīng)當(dāng)采用數(shù)組起步。但實(shí)際上,只有矩陣計(jì)算特征香菜才具有意義的,特征向量是矩陣的一重大點(diǎn)。以上結(jié)果的輸出為:
[ 4. 1. -2.]
[[-0.66666667 -0.66666667 0.33333333]
[ 0.66666667 -0.33333333 0.66666667]
[-0.33333333 0.66666667 0.66666667]]
<class 'numpy.ndarray'>
<class 'numpy.matrix'>
? ? ? ? 可以看到,特征值輸出的結(jié)果為數(shù)組,特征向量輸出的結(jié)果為矩陣。在這里需要注意的是,三個(gè)特征向量是按照列查看的,也就是三列特征值,水平堆疊hstack形成一個(gè)特征矩陣。
????????在線性代數(shù)中,我們運(yùn)用史密斯正交法,將相關(guān)向量化為無(wú)關(guān)向量,并單位正交化,可以得到一個(gè)全新矩陣,此矩陣乃是特征矩陣。接下來(lái)可以進(jìn)行驗(yàn)證:
# 特征之一特征向量的相互計(jì)算
# 計(jì)算矩陣與特征向量乘積
print(np.dot(matr_esp, st_matr))
# 計(jì)算特征值與特征向量的乘積
print(nmd_matr*st_matr)
# 驗(yàn)證二者是否相等
print(np.isclose(np.dot(matr_esp, st_matr), nmd_matr*st_matr))
# 計(jì)算其行列式的值
print(np.linalg.det(matr_esp-np.eye(3, 3)*nmd_matr))
? ? ? ? 輸出結(jié)果如下:
[[-2.66666667 -0.66666667 -0.66666667]
[ 2.66666667 -0.33333333 -1.33333333]
[-1.33333333 0.66666667 -1.33333333]]
[[-2.66666667 -0.66666667 -0.66666667]
[ 2.66666667 -0.33333333 -1.33333333]
[-1.33333333 0.66666667 -1.33333333]]
[[ True True True]
[ True True True]
[ True True True]]
-6.217248937900884e-15
????????其結(jié)果成立,便為特征值。滿足原表達(dá)式。
?6、計(jì)算逆矩陣? ? ? ??
? ? ? ? 接下來(lái)是最后一個(gè)計(jì)算知識(shí)點(diǎn),也是線性代數(shù)中重點(diǎn),且每年的必考點(diǎn)之一:計(jì)算逆矩陣。我們知道,常規(guī)的逆矩陣及算法有三種:(1)用定義求逆矩陣;(2)用伴隨矩陣求逆;(3)初等變換——行變換增廣矩陣化單位陣求逆矩陣。
? ? ? ? 而在python中,計(jì)算逆矩陣的方法便為初等變換,這里簡(jiǎn)單書(shū)寫(xiě)提醒原則,也是我自己在回顧一遍:
????????當(dāng)兩個(gè)方陣A和B進(jìn)行乘法(位置不可交換),A·B=B·A=E,則=B,因此,基于此邏輯,我么可以將一個(gè)單位陣與B進(jìn)行增廣,達(dá)成B|E,通過(guò)初等恒變換,將B矩陣化為單位陣E通過(guò)恒等變換得到的結(jié)果自然為A的逆矩陣,其等價(jià)于B|E=E|。
? ? ? ?其原理在于,我們?cè)趯化為單位陣的過(guò)程中,實(shí)際上經(jīng)歷了以下變化:B——>BA——>E,此過(guò)程中,E的變化為:E——>E——>。因此,上述結(jié)果成立。這是求B的逆矩陣A時(shí)滿足的結(jié)果,以結(jié)果逆推其逆矩陣。
? ? ? ? 在python中,將此過(guò)程表達(dá)出來(lái)的仍然是linalg模塊中的函數(shù)inv()。其表達(dá)式為:逆=np.linalg.inv(matr)。此計(jì)算,就必定采用矩陣作為基礎(chǔ),這一點(diǎn)與計(jì)算矩陣的特征值與特征向量是具有一定區(qū)別的。
# 計(jì)算矩陣的逆矩陣
init_matr = np.matrix([[1, 2, 3], [4, 5, 6], [7, 8, 0]])
contr_matr = np.linalg.inv(init_matr)
print(contr_matr)
# 若驗(yàn)證結(jié)果可以使用是否相等
print(init_matr*contr_matr) ; print(contr_matr*init_matr)
print(np.isclose(init_matr*contr_matr, contr_matr*init_matr))
? ? ? ? 其輸出的結(jié)果為:
[[-1.77777778 0.88888889 -0.11111111]
[ 1.55555556 -0.77777778 0.22222222]
[-0.11111111 0.22222222 -0.11111111]]
[[ 1.00000000e+00 5.55111512e-17 1.38777878e-17]
[ 5.55111512e-17 1.00000000e+00 2.77555756e-17]
[ 1.77635684e-15 -8.88178420e-16 1.00000000e+00]]
[[ 1.00000000e+00 -1.11022302e-16 0.00000000e+00]
[ 8.32667268e-17 1.00000000e+00 2.22044605e-16]
[ 6.93889390e-17 0.00000000e+00 1.00000000e+00]]
[[ True True True]
[ True True True]
[ True True True]]
? ? ? ? 至此,其逆矩陣我們便輕松拿捏了。
二、矩陣的應(yīng)用拓展
?1、求解線性方程組
? ? ? ? 在線性代數(shù)中,求解線性方程組是一個(gè)難點(diǎn),其對(duì)于線性方程組要有一定的判定方可著實(shí)對(duì)方程組進(jìn)行解答,這也是線性方程組的一個(gè)特殊點(diǎn)與重點(diǎn)所在。
????????我們求解線性方程組的解步驟為:
? ? ? ? (1)化階梯型;(2)找到最大線性無(wú)關(guān)組組成矩陣;(3)求自由變量s=n(列向量個(gè)數(shù))-r(階梯矩陣的秩);(4)取自由變量的單位矩陣;(5)計(jì)算出原始的列向量的每一個(gè)值,由此得到齊次線性方程的通解,至此,齊次線性方程組結(jié)束;(6)此步為非齊次特解的求法,通過(guò)自定自由元素的值,得到一個(gè)特解,非齊次線性方程組的解便為齊次的解+非齊次的特解。
? ? ? ? 又是一個(gè)巨大的運(yùn)算量,然而此過(guò)程在python中numpy已經(jīng)有函數(shù)加以計(jì)算,仍然是linalg模塊,solve()函數(shù)得到輕松解決。
# 唯一解
A = np.matrix([[3,1],[1,2]])
b = np.matrix([9,8]).T
x = np.linalg.solve(A,b)
print(x)
print(np.isclose(A*x,b))
# 最小二乘解:返回解、余項(xiàng)、a的秩、a的奇異值
print(np.linalg.lstsq(A,b,rcond= 1))
? ? ? ? 我們已經(jīng)知道線性方程組的解法為初始矩陣A與b的列項(xiàng)倆個(gè)的增廣矩陣之間的關(guān)系。因此,solve函數(shù)就在這期間將a單獨(dú)拿出來(lái)作為一個(gè)矩陣運(yùn)用solve函數(shù)便可直接得到線性方程組的解。但此方案的局限性在于只適用于有解且只有唯一解惡的線性方程組。其解答為:
[[2.]
[3.]]
[[ True]
[ True]]
(matrix([[2.],
[3.]]), matrix([], shape=(1, 0), dtype=float64), 2, array([3.61803399, 1.38196601]))
?????????而對(duì)于多解的線性方程組,無(wú)論是齊次,還是非齊次,都涉及到很多交叉的變化,這里不再基礎(chǔ)中提到,將在后面的numpy進(jìn)階中作為示例列舉與學(xué)習(xí)。
?2、矩陣的向量化
? ? ? ? 矩陣無(wú)法直接使用math庫(kù)里面的階乘函數(shù)factorial(),而numpy庫(kù)也無(wú)內(nèi)置函數(shù)解決,因此,可以用numpy中的vectorize()將矩陣向量化,便可使用階乘函數(shù)。具體代碼如下:
# 矩陣向量化
import math
matr =np.matrix([[1,2,3],[4,5,6]])
# 這里不能直接使用會(huì)報(bào)錯(cuò)
# math.factorial(matr)
# 正確方法先采用向量化
VecFactorial = np.vectorize(math.factorial())
print(VecFactorial(matr))
? ? ? ? 最后可得到其階乘的結(jié)果:
[[ 1 2 6]
[ 24 120 720]]
?3、奇異值分解
? ? ? ? 接著,是今天的最后一個(gè)內(nèi)容,奇異值分解,我們知道,存在可逆矩陣P、Q有(對(duì)角矩陣),則由此,通過(guò)奇異值分解,將矩陣A分解為多個(gè)更小的矩陣的乘積,這也是降維的一大方法。
? ? ? ? 這一過(guò)程可以通過(guò)nmpy中l(wèi)inalg中的svd()函數(shù)完成,可以將a=usv,直接可用svd函數(shù)表示,其中s便為奇異值。
# 返回矩陣的奇異值
a =np.matrix([[1,2,3],[4,5,6],[7,8,9]])
u,s,v = np.linalg.svd(a)
print(s)
? ? ? ? 其結(jié)果為:s=[1.68481034e+01 1.06836951e+00 4.41842475e-16]。文章來(lái)源:http://www.zghlxwxcb.cn/news/detail-768712.html
????????至此,我們的矩陣到此結(jié)束,numpy基礎(chǔ)知識(shí)也到此趨近于結(jié)束。每天學(xué)習(xí),點(diǎn)滴進(jìn)步!文章來(lái)源地址http://www.zghlxwxcb.cn/news/detail-768712.html
到了這里,關(guān)于Python庫(kù)第一課:基礎(chǔ)Numpy知識(shí)(下):矩陣的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!