講解Python在線性代數中的應用,包括:
一、矩陣創建
先導入Numpy模塊,在下文中均采用np代替numpy
1 import numpy as np
矩陣創建有兩種方法,一是使用np.mat函數或者np.matrix函數,二是使用數組代替矩陣,實際上官方文檔建議我們使用二維數組代替矩陣來進行矩陣運算;因為二維數組用得較多,而且基本可取代矩陣。
1 >>> a = np.mat([[1, 2, 3], [4, 5, 6]]) #使用mat函數創建一個2X3矩陣 2 >>> a 3 matrix([[1, 2, 3], 4 [4, 5, 6]]) 5 >>> b = np.matrix([[1, 2, 3], [4, 5, 6]])#np.mat和np.matrix等價 6 >>> b 7 matrix([[1, 2, 3], 8 [4, 5, 6]]) 9 >>> a.shape #使用shape屬性可以獲取矩陣的大小 10 (2, 3)
1 >>> c = np.array([[1, 2, 3], [4, 5, 6]]) #使用二維數組代替矩陣,常見的操作通用 2 >>> c#注意c是array類型,而a是matrix類型 3 array([[1, 2, 3], 4 [4, 5, 6]])
單位陣的創建
1 >>> I = np.eye(3) 2 >>> I 3 array([[ 1., 0., 0.], 4 [ 0., 1., 0.], 5 [ 0., 0., 1.]])
矩陣元素的存取操作:
1 >>> a[0]#獲取矩陣的某一行 2 matrix([[1, 2, 3]]) 3 >>> a[:, 0].reshape(-1, 1)#獲取矩陣的某一列 4 matrix([[1], 5 [4]]) 6 >>> a[0, 1]#獲取矩陣某個元素 7 2
二、矩陣乘法和加法
矩陣類型,在滿足乘法規則的條件下可以直接相乘
1 >>> A = np.mat([[1, 2, 3], [3, 4, 5], [6, 7, 8]])#使用mat函數 2 >>> B = np.mat([[5, 4, 2], [1, 7, 9], [0, 4, 5]]) 3 >>> A #注意A, B都是matrix類型,可以使用乘號,如果是array則不可以直接使用乘號 4 matrix([[1, 2, 3], 5 [3, 4, 5], 6 [6, 7, 8]]) 7 >>> B 8 matrix([[5, 4, 2], 9 [1, 7, 9], 10 [0, 4, 5]]) 11 >>> A * B#學過線性代數的都知道:A * B != B * A 12 matrix([[ 7, 30, 35], 13 [ 19, 60, 67], 14 [ 37, 105, 115]]) 15 >>> B * A 16 matrix([[ 29, 40, 51], 17 [ 76, 93, 110], 18 [ 42, 51, 60]])
如果是使用數組代替矩陣進行運算則不可以直接使用乘號,應使用dot()函數。dot函數用於矩陣乘法,對於二維數組,它計算的是矩陣乘積,對於一維數組,它計算的是內積。
1 >>> C = np.array([[1, 2, 3], [3, 4, 5], [6, 7, 8]]) 2 >>> D = np.array([[5, 4, 2], [1, 7, 9], [0, 4, 5]]) 3 >>> C #C, D都是array類型,不能直接使用乘號,應該使用dot()函數 4 array([[1, 2, 3], 5 [3, 4, 5], 6 [6, 7, 8]]) 7 >>> D 8 array([[5, 4, 2], 9 [1, 7, 9], 10 [0, 4, 5]]) 11 #>>> C * D, Error, 注意這不是矩陣乘法!!! 12 >>> np.dot(C, D)#正確的寫法,得到的結果和上一段代碼的第11行的結果的一樣的。 13 array([[ 7, 30, 35], 14 [ 19, 60, 67], 15 [ 37, 105, 115]])
如何理解對於一維數組,它計算的是內積???
注意:在線性代數里面講的維數和數組的維數不同,如線代中提到的n維行向量在Python中是一維數組,而線代中的n維列向量在Python中是一個shape為(n, 1)的二維數組!
第16行,第18行:F是一維數組,G是二維數組,維數不同,個人認為相乘沒有意義,但是16行沒有錯誤,18行報錯。關於dot()的乘法規則見:NumPy-快速處理數據--矩陣運算
1 >>> E = np.array([1, 2, 3]) 2 >>> F = np.array([4, 3, 9]) 3 >>> E.shape#E,F都是一維數組 4 (3,) 5 >>> np.dot(E, F) 6 37 7 >>> np.dot(F, E) 8 37 9 >>> G = np.array([4, 3, 9]).reshape(-1, 1) 10 >>> G 11 array([[4], 12 [3], 13 [9]]) 14 >>> G.shape 15 (3, 1) 16 >>> np.dot(F, G)#因此dot(F, G)不再是內積,而是一個只有一個元素的數組 17 array([106]) 18 >>> np.dot(G, F)#ValueError: shapes (3,1) and (3,) not aligned: 1 (dim 1) != 3 (dim 0) 19 >>> E.shape = (1, -1)#把E改為二維數組 20 >>> E 21 array([[1, 2, 3]]) 22 >>> E.shape 23 (1, 3) 24 >>> np.dot(G, E)#3×1的G向量乘以1×3的E向量會得到3×3的矩陣 25 array([[ 4, 8, 12], 26 [ 3, 6, 9], 27 [ 9, 18, 27]])
矩陣的加法運算
1 >>> A + B#矩陣的加法對matrix類型和array類型是通用的 2 matrix([[ 6, 6, 5], 3 [ 4, 11, 14], 4 [ 6, 11, 13]]) 5 >>> C + D 6 array([[ 6, 6, 5], 7 [ 4, 11, 14], 8 [ 6, 11, 13]])
矩陣的數乘運算
1 >>> 2 * A#矩陣的數乘對matrix類型和array類型是通用的 2 matrix([[ 2, 4, 6], 3 [ 6, 8, 10], 4 [12, 14, 16]]) 5 >>> 2 * C 6 array([[ 2, 4, 6], 7 [ 6, 8, 10], 8 [12, 14, 16]])
三、矩陣的轉置
1 >>> A = np.array([[1, 2, 3], [3, 4, 5], [6, 7, 8]]) 2 >>> B = np.array([[5, 4, 2], [1, 7, 9], [0, 4, 5]]) 3 >>> A 4 array([[1, 2, 3], 5 [3, 4, 5], 6 [6, 7, 8]]) 7 >>> A.T #A的轉置 8 array([[1, 3, 6], 9 [2, 4, 7], 10 [3, 5, 8]]) 11 >>> A.T.T#A的轉置的轉置還是A本身 12 array([[1, 2, 3], 13 [3, 4, 5], 14 [6, 7, 8]])
驗證矩陣轉置的性質:(A±B)'=A'±B'
1 >>> (A + B).T 2 array([[ 6, 4, 6], 3 [ 6, 11, 11], 4 [ 5, 14, 13]]) 5 >>> A.T + B.T 6 array([[ 6, 4, 6], 7 [ 6, 11, 11], 8 [ 5, 14, 13]])
驗證矩陣轉置的性質:(KA)'=KA'
1 >>> 10 * (A.T) 2 array([[10, 30, 60], 3 [20, 40, 70], 4 [30, 50, 80]]) 5 >>> (10 * A).T 6 array([[10, 30, 60], 7 [20, 40, 70], 8 [30, 50, 80]])
驗證矩陣轉置的性質:(A×B)'= B'×A'
1 >>> np.dot(A, B).T 2 array([[ 7, 19, 37], 3 [ 30, 60, 105], 4 [ 35, 67, 115]]) 5 >>> np.dot(B.T, A.T) 6 array([[ 7, 19, 37], 7 [ 30, 60, 105], 8 [ 35, 67, 115]])
四、方陣的跡
方陣的跡就是主對角元素之和,使用trace()函數獲得方陣的跡:
1 >>> A 2 array([[1, 2, 3], 3 [3, 4, 5], 4 [6, 7, 8]]) 5 >>> B 6 array([[5, 4, 2], 7 [1, 7, 9], 8 [0, 4, 5]]) 9 >>> np.trace(A) # A的跡等於A.T的跡 10 13 11 >>> np.trace(A.T) 12 13 13 >>> np.trace(A+B)# 和的跡 等於 跡的和 14 30 15 >>> np.trace(A) + np.trace(B) 16 30
五、計算行列式
1 >>> A 2 array([[1, 2], 3 [1, 3]]) 4 >>> np.linalg.det(A) 5 1.0
六、逆矩陣/伴隨矩陣
若A存在逆矩陣(滿足det(A) != 0,或者A滿秩),使用linalg.inv求得方陣A的逆矩陣
1 import numpy as np 2 >>> A = np.array([[1, -2, 1], [0, 2, -1], [1, 1, -2]]) 3 >>> A 4 array([[ 1, -2, 1], 5 [ 0, 2, -1], 6 [ 1, 1, -2]]) 7 >>> A_det = np.linalg.det(A) #求A的行列式,不為零則存在逆矩陣 8 >>> A_det 9 -3.0000000000000004 10 >>> A_inverse = np.linalg.inv(A) #求A的逆矩陣 11 >>> A_inverse 12 array([[ 1. , 1. , 0. ], 13 [ 0.33333333, 1. , -0.33333333], 14 [ 0.66666667, 1. , -0.66666667]]) 15 >>> np.dot(A, A_inverse) #A與其逆矩陣的乘積為單位陣 16 array([[ 1., 0., 0.], 17 [ 0., 1., 0.], 18 [ 0., 0., 1.]]) 19 >>> A_companion = A_inverse * A_det #求A的伴隨矩陣 20 >>> A_companion 21 array([[-3., -3., -0.], 22 [-1., -3., 1.], 23 [-2., -3., 2.]])
七、解一元線性方程
使用np.linalg.solve()解一元線性方程組,待解方程為:
x + 2y + z = 7 2x - y + 3z = 7 3x + y + 2z =18
1 >>> import numpy as np 2 >>> A = np.array([[1, 2, 1], [2, -1, 3], [3, 1, 2]]) 3 >>> A #系數矩陣 4 array([[ 1, 2, 1], 5 [ 2, -1, 3], 6 [ 3, 1, 2]]) 7 >>> B = np.array([7, 7, 18]) 8 >>> B 9 array([ 7, 7, 18]) 10 >>> x = np.linalg.solve(A, B) 11 >>> x 12 array([ 7., 1., -2.]) 13 >>> np.dot(A, x)#檢驗正確性,結果為B 14 array([ 7., 7., 18.])
使用np.allclose()檢測兩個矩陣是否相同:
1 >>> np.allclose(np.dot(A, x), B)#檢驗正確性 2 True
使用 help(np.allclose) 查看 allclose() 的用法:
allclose(a, b, rtol=1e-05, atol=1e-08) Parameters ---------- a, b : array_like Input arrays to compare. rtol : float The relative tolerance parameter (see Notes). atol : float The absolute tolerance parameter (see Notes). Returns ------- allclose : bool Returns True if the two arrays are equal within the given tolerance; False otherwise.
八、計算矩陣距離
矩陣的距離,這里是的是歐幾里得距離,其他距離表示方法我們以后再談,這里說一下如何計算兩個形狀相同矩陣之間的距離。
1 >>> A = np.array([[0, 1], [1, 0]])#先創建兩個矩陣 2 >>> B = np.array([[1, 1], [1, 1]]) 3 >>> C = A - B #計算距離矩陣C 4 >>> C 5 array([[-1, 0], 6 [ 0, -1]]) 7 >>> D = np.dot(C, C)#距離矩陣的平方 8 >>> E = np.trace(D) #計算矩陣D的跡 9 >>> E 10 2 11 >>> E ** 0.5 #將E開平方得到距離 12 1.4142135623730951
關於計算矩陣距離我也不理解。網上看的帖子,先記下來
九、矩陣的秩
numpy包中的linalg.matrix_rank方法計算矩陣的秩:
1 >>> import numpy as np 2 >>> I = np.eye(3)#先創建一個單位陣 3 >>> I 4 array([[ 1., 0., 0.], 5 [ 0., 1., 0.], 6 [ 0., 0., 1.]]) 7 >>> np.linalg.matrix_rank(I)#秩 8 3 9 >>> I[1, 1] = 0#將該元素置為0 10 >>> I 11 array([[ 1., 0., 0.], 12 [ 0., 0., 0.], 13 [ 0., 0., 1.]]) 14 >>> np.linalg.matrix_rank(I)#此時秩變成2 15 2
十、求方陣的特征值特征向量
1 >>> import numpy as np 2 >>> x = np.diag((1, 2, 3))#創建一個對角矩陣! 3 >>> x 4 array([[1, 0, 0], 5 [0, 2, 0], 6 [0, 0, 3]]) 7 >>> a,b = np.linalg.eig(x)#特征值保存在a中,特征向量保存在b中 8 >>> a 9 array([ 1., 2., 3.]) 10 >>> b 11 array([[ 1., 0., 0.], 12 [ 0., 1., 0.], 13 [ 0., 0., 1.]])
根據公式 Ax = λx 檢驗特征值與特征向量是否正確:
1 for i in range(3):#方法一 2 if np.allclose(np.dot(a[i], b[:, i]), x[:, i]):#np.allclose()方法在第七節提到過 3 print 'Right' 4 else: 5 print 'Error' 6 7 for i in range(3):#方法二 8 if (np.dot(a[i], b[:, i]) == x[:, i]).all(): 9 print 'Right' 10 else: 11 print 'Error'
注意,如果寫成 if np.dot(a[i], b[:, i]) == x[:, i]: 是錯誤的:(矩陣包含有多個值,應該使用a.any()或者a.all()判斷)
ValueError: The truth value of an array with more than one element is ambiguous. Use a.any() or a.all()
十一、判斷正定矩陣
設M是n階方陣,如果對任何非零向量z,都有z'Mz> 0,其中z' 表示z的轉置,就稱M正定矩陣。
判定定理1:對稱陣A為正定的充分必要條件是:A的特征值全為正。
判定定理2:對稱陣A為正定的充分必要條件是:A的各階順序主子式都為正。
判定定理3:任意陣A為正定的充分必要條件是:A合同於單位陣。
下面用定理1判斷對稱陣是否為正定陣
1 >>> import numpy as np 2 >>> A = np.arange(16).reshape(4, 4) 3 >>> A 4 array([[ 0, 1, 2, 3], 5 [ 4, 5, 6, 7], 6 [ 8, 9, 10, 11], 7 [12, 13, 14, 15]]) 8 >>> A = A + A.T #將方陣轉換成對稱陣 9 >>> A 10 array([[ 0, 5, 10, 15], 11 [ 5, 10, 15, 20], 12 [10, 15, 20, 25], 13 [15, 20, 25, 30]]) 14 >>> B = np.linalg.eigvals(A)#求B的特征值,注意:eig()是求特征值特征向量 15 >>> B 16 array([ 6.74165739e+01 +0.00000000e+00j, 17 -7.41657387e+00 +0.00000000e+00j, 18 2.04219701e-15 +3.94306094e-15j, 19 2.04219701e-15 -3.94306094e-15j]) 20 21 if np.all(B>0): #判斷是不是所有的特征值都大於0,用到了all函數,顯然對稱陣A不是正定的 22 print 'Yes'
創建一個對角元素都為正的對角陣,它一定是正定的:
1 >>> A = np.diag((1, 2, 3))#創建對角陣,其特征值都為正 2 >>> B = np.linalg.eigvals(A)#求特征值 3 >>> B 4 array([ 1., 2., 3.]) 5 >>> if np.all(B>0):#判斷特征值是否都大於0 6 print 'Yes'
網上查到更簡便的方法是對對稱陣進行cholesky分解,如果像這樣沒有提示出錯,就說明它是正定的。如果提示出錯,就說明它不是正定矩陣,你可以使用try函數捕獲錯誤值:
1 # -*- coding: utf-8 -*- 2 import numpy as np 3 4 A = np.arange(16).reshape(4, 4) 5 A = A + A.T 6 print A 7 try: 8 B = np.linalg.cholesky(A) 9 except : 10 print ('不是正定矩陣,不能進行cholesky分解。')
當不能進行cholesky分解時,出現的異常是: LinAlgError: Matrix is not positive definite ,但是但是LinAlgError不是Python標准異常,因此不能使用這條語句。
1 except LinAlgError as reason: 2 print ('不是正定矩陣,不能進行cholesky分解。\n出錯原因是:' + str(reason))