人工智能必备数学知识学习笔记15:特征值与特征向量

 

  •  什么是特征值和特征向量

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 



 

 

  •  特征值和特征向量的相关概 

     

 

 

 

 

 

 

 

 

 

 

 



  • 特征值与特征向量的性质

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 



直观理解特征值与特征向量

 

 

 

 

 

 

 

 

 

 

 

 

 



  • “不简单”的特征值

 

 

 

 

 

 

 

 

 

 

代码实现:

 

 

 

 

 

 1.文件 main_eigen.py 编写代码:

 1 #在numpy中求解特征值与特征向量
 2 import numpy as np
 3 from numpy.linalg import eig
 4 
 5 if __name__ == "__main__":
 6 
 7     A1 = np.array([[4, -2],
 8                    [1, 1]]);
 9     eigenvalues1, eigenvectors1 = eig(A1)#求取矩阵的特征值与特征向量  eigenvalues:特征值 eigenvectors:特征向量
10     print(eigenvalues1) #特征值
11     print(eigenvectors1)#特征向量
12     print()
13 
14     # 关于y=x翻转
15     A2 = np.array([[0, 1],
16                    [1, 0]]);
17     eigenvalues2, eigenvectors2 = eig(A2)#求取矩阵的特征值与特征向量  eigenvalues:特征值 eigenvectors:特征向量
18     print(eigenvalues2) #特征值
19     print(eigenvectors2)#特征向量
20     print()
21 
22     # 旋转90
23     A3 = np.array([[0, -1],
24                    [1, 0]]);
25     eigenvalues3, eigenvectors3 = eig(A3)#求取矩阵的特征值与特征向量  eigenvalues:特征值 eigenvectors:特征向量
26     print(eigenvalues3) #特征值
27     print(eigenvectors3)#特征向量
28     print()
29 
30     # 单位矩阵
31     A4 = np.array([[1, 0],
32                    [0, 1]]);
33     eigenvalues4, eigenvectors4 = eig(A4)#求取矩阵的特征值与特征向量  eigenvalues:特征值 eigenvectors:特征向量
34     print(eigenvalues4) #特征值
35     print(eigenvectors4)#特征向量
36     print()
37 
38     # 几何重数为1
39     A5 = np.array([[3, 1],
40                    [0, 3]]);
41     eigenvalues5, eigenvectors5 = eig(A5)#求取矩阵的特征值与特征向量  eigenvalues:特征值 eigenvectors:特征向量
42     print(eigenvalues5) #特征值
43     print(eigenvectors5)#特征向量
44     print()
45 
46     

2.文件 main_eigen.py 运行结果:

 1 /Users/liuxiaoming/PycharmProjects/LinearAlgebra/venv/bin/python /Applications/PyCharm.app/Contents/plugins/python/helpers/pydev/pydevconsole.py --mode=client --port=62920
 2 import sys; print('Python %s on %s' % (sys.version, sys.platform))
 3 sys.path.extend(['/Users/liuxiaoming/PycharmProjects/LinearAlgebra'])
 4 PyDev console: starting.
 5 Python 3.8.2 (v3.8.2:7b3ab5921f, Feb 24 2020, 17:52:18) 
 6 [Clang 6.0 (clang-600.0.57)] on darwin
 7 runfile('/Users/liuxiaoming/PycharmProjects/LinearAlgebra/main_eigen.py', wdir='/Users/liuxiaoming/PycharmProjects/LinearAlgebra')
 8 [3. 2.]
 9 [[0.89442719 0.70710678]
10  [0.4472136  0.70710678]]
11 [ 1. -1.]
12 [[ 0.70710678 -0.70710678]
13  [ 0.70710678  0.70710678]]
14 [0.+1.j 0.-1.j]
15 [[0.70710678+0.j         0.70710678-0.j        ]
16  [0.        -0.70710678j 0.        +0.70710678j]]
17 [1. 1.]
18 [[1. 0.]
19  [0. 1.]]
20 [3. 3.]
21 [[ 1.00000000e+00 -1.00000000e+00]
22  [ 0.00000000e+00  6.66133815e-16]]

 



  • 矩阵相似和背后的重要含义

 

 

 

 

 

 

 

 

 

 

 

 



  • 矩阵对角 

     

 

 

 

 

 

 

 

 

 

 代码实现:

 

 1.调用文件 Matrix.py :

  1 #矩阵类
  2 from playLA.Vector import Vector
  3 
  4 
  5 class Matrix:
  6     # 参数2:二维数组
  7     def __init__(self, list2d):
  8         if isinstance(list2d[0], list):  #若二维数组为 list 集合
  9             self._values = [row[:] for row in list2d] # 将数组变为矩阵
 10         elif isinstance(list2d[0], Vector): #若二维数组 为向量时
 11             self._values = [row.underlying_list() for row in list2d] #将数组中的每一行作为一个数组放到一个大的数组中
 12 
 13     #矩阵类方法:返回一个r行c列的零矩阵:参数1:为零的类对象
 14     @classmethod
 15     def zero(cls,r,c):
 16         return cls([[0] * c for _ in range(r)]) #创建一个r行c列为零的一个列表
 17 
 18     #单位矩阵类方法:返回一个n行n列的单位矩阵
 19     @classmethod
 20     def identity(cls, n):
 21         m = [[0] * n for _ in range(n)] #此处 m 代表有 n 行,每一行有 n 个 0
 22         for i in range(n):
 23             m[i][i] = 1  #此处代表将矩阵 m 的 第i行的第i个元素赋值为1
 24         return cls(m)
 25 
 26     #返回矩阵的转置矩阵
 27     def T(self):
 28         #将每一行的相同位置(每一列)元素提取出来变为行组成新的矩阵
 29         return Matrix([[e for e in self.col_vector(i)]
 30                        for i in range(self.col_num())])
 31 
 32     #返回两个矩阵的加法结果
 33     def __add__(self, another):
 34         # 校验两个矩阵的形状为一致(行数、列数一致)
 35         assert self.shape() == another.shape(), \
 36             "Error in adding. Shape of matrix must be same."
 37         # 根据矩阵的加法公式:两个矩阵对应的每一行的每一个元素相加,获得新的矩阵(遍历两个矩阵对应的每一个行每个元素进行相加<第二步>,外部再遍历该矩阵的行数(循环的次数)<第一步>)
 38         return Matrix([[a+b for a,b in zip(self.row_vector(i),another.row_vector(i))]
 39                        for i in range(self.row_num())])
 40 
 41     # 返回两个矩阵的减法结果
 42     def __sub__(self, another):
 43         assert self.shape() == another.shape(), \
 44             "Error in subtracting. Shape of matrix must be same."
 45         return Matrix([[a - b for a, b in zip(self.row_vector(i), another.row_vector(i))]
 46                        for i in range(self.row_num())])
 47 
 48     #返回两个矩阵的乘法结果(矩阵乘以矩阵)
 49     def dot(self,another):
 50         if isinstance(another,Vector):#判断是否为向量:矩阵与向量的乘法
 51             assert self.col_num() == len(another),\
 52                 "Error in Matrix_Vector Multiplication." #矩阵与向量的乘法错误
 53             return Vector([self.row_vector(i).dot(another) for i in range(self.row_num())])
 54         if isinstance(another,Matrix):#判断是否为矩阵:矩阵与矩阵的乘法
 55             assert self.col_num() == another.row_num(),\
 56                 "Error in Matrix-Matrix Multiplication." #矩阵与矩阵的乘法错误
 57             # 将矩阵的每一行与另一矩阵的每一列进行向量间的点乘
 58             return Matrix([[self.row_vector(i).dot(another.col_vector(j)) for j in range(another.col_num())]
 59                             for i in range(self.row_num())])
 60 
 61     #返回矩阵的数量乘结果(矩阵乘以数字):self * k
 62     def __mul__(self, k):
 63         #通过遍历每一行的每个元素e后分别乘以k<第一步>,外部再遍历该矩阵的行数(循环的次数)<第二步>
 64         return Matrix([[e * k for e in self.row_vector(i)]
 65                        for i in range(self.row_num())])
 66 
 67     # 返回矩阵的数量乘结果(数字乘以矩阵):k * self
 68     def __rmul__(self, k):
 69         return self * k
 70 
 71     #返回数量除法的结果矩阵:self / k
 72     def __truediv__(self, k):
 73         return (1 / k) * self
 74 
 75     #返回矩阵取正的结果
 76     def __pos__(self):
 77         return 1 * self
 78 
 79     #返回矩阵取负的结果
 80     def __neg__(self):
 81         return -1 * self
 82 
 83     #返回矩阵的第index个行向量
 84     def row_vector(self,index):
 85         return Vector(self._values[index])
 86 
 87     # 返回矩阵的第index个列向量
 88     def col_vector(self, index):
 89         return Vector([row[index] for row in self._values])
 90 
 91     #返回矩阵pos位置的元素(根据元素的位置取元素值) :参数2:元组
 92     def __getitem__(self, pos):
 93         r,c = pos
 94         return self._values[r][c]
 95 
 96     #返回矩阵的元素个数
 97     def size(self):
 98         r,c = self.shape()
 99         return r*c
100 
101     #返回矩阵行数
102     def row_num(self):
103         return self.shape()[0]
104 
105     __len__ = row_num
106 
107     #返回矩阵列数
108     def col_num(self):
109         return self.shape()[1]
110 
111     #返回矩阵形状:(行数,列数)
112     def shape(self):
113         return len(self._values),len(self._values[0])
114 
115     #矩阵展示
116     def __repr__(self):
117         return "Matrix({})".format(self._values)
118 
119     __str__ = __repr__

2.调用文件 LinearSystem.py :

  1 from playLA.Matrix import Matrix
  2 from playLA.Vector import Vector
  3 from playLA._global import is_zero
  4 
  5 
  6 #线性系统
  7 class LinearSystem:
  8 
  9     #初始化函数:参数A:增广矩阵的等号左边的系数 参数b:增广矩阵的等号右边的值(方程右边的结果)
 10     def __init__(self, A, b):
 11         #判断 b为None 或者 矩阵A的行数等于b的列数
 12         assert b is None or A.row_num() == len(b),\
 13             "row number of A must be equal to the length of b"
 14         self._m = A.row_num()#行数
 15         self._n = A.col_num()#列数
 16 
 17         #判断若b为空时,则该矩阵为A矩阵 TODO:2020-08-22
 18         if b is None:
 19             self.Ab = [A.row_vector(i) for i in range(self._m)]
 20 
 21         if isinstance(b, Vector):#如果等号右侧方程结果为列向量时
 22             #增广矩阵
 23             self.Ab = [Vector(A.row_vector(i).underlying_list() + [b[i]])
 24                        for i in range(self._m)]
 25 
 26         if isinstance(b, Matrix):#如果等号右侧方程结果为单位矩阵时
 27             #增广矩阵
 28             self.Ab = [Vector(A.row_vector(i).underlying_list() + b.row_vector(i).underlying_list())
 29                        for i in range(self._m)]
 30         #主元
 31         self.pivots = []
 32 
 33     #寻找最大主源系数
 34     def _max_row(self, index_i, index_j, n):
 35         best, ret = self.Ab[index_i][index_j], index_i #存储第index行index列的元素值与当前index的值
 36         for i in range(index_i + 1, n): #从index+1开始一直遍历到n
 37             if self.Ab[i][index_j] > best:
 38                 best, ret = self.Ab[i][index_j], i
 39         return ret
 40 
 41     #高斯—约旦消元法-前向过程
 42     def _forward(self):
 43 
 44        i,k = 0,0
 45        while i < self._m and k < self._n:
 46             #看Ab[i][k]位置是否为主元
 47             max_row = self._max_row(i, k, self._m)#寻找最大主源系数的行数
 48             self.Ab[i], self.Ab[max_row] = self.Ab[max_row],self.Ab[i] #行交换操作
 49 
 50             if is_zero(self.Ab[i][k]):#判断此时该值是否为0
 51                 k += 1
 52             else:
 53                 #将主元归为一
 54                 self.Ab[i] = self.Ab[i] / self.Ab[i][k]
 55                 #将当前主源下的所有行对应主源列的元素全部归为0 :也就是第一次循环会将该主源下的所有对应列变为0,第二次循环会将第二次主源列下的所有对应列变为0
 56                 for j in range(i + 1, self._m):
 57                     self.Ab[j] =self.Ab[j] -self.Ab[j][k] * self.Ab[i]#该主源行下的所有行减去主源行
 58                 self.pivots.append(k)
 59                 i += 1
 60 
 61     #高斯-约旦消元法-后向过程
 62     def _backward(self):
 63         n = len(self.pivots)
 64         #n = self._m #行数
 65         for i in range(n-1, -1, -1): #反向遍历且 从参数1的位置遍历到参数2的位置,也就是从倒数第一个位置遍历到第一个位置,参数3为步长(遍历的方向及单位)
 66             k = self.pivots[i]
 67             #Ab[i][k]为主源
 68             for j in range(i-1, -1, -1):
 69                 self.Ab[j] = self.Ab[j] - self.Ab[j][k] * self.Ab[i]#该主源行上的所有行减去主源行
 70 
 71     #高斯-约旦消元法:如果有解,返回True;如果没有解,返回False
 72     def gauss_jordan_elimination(self):
 73         # 高斯—约旦消元法-前向过程
 74         self._forward()
 75         # 高斯-约旦消元法-后向过程
 76         self._backward()
 77         for i in range(len(self.pivots), self._m):#此处为最后一行的非零行下一行的全零行的结果值不为零的判断   0.0 0.0 | 5.0
 78             if not is_zero(self.Ab[i][-1]):
 79                 return False
 80         return True
 81 
 82     # 打印结果(求每个未知数的值)
 83     def fancy_print(self):
 84         for i in range(self._m):
 85             print(" ".join(str(self.Ab[i][j]) for j in range(self._n)),end=" ")
 86             print("|",self.Ab[i][-1])
 87 
 88 
 89 #求增广矩阵的逆
 90 def inv(A):
 91 
 92     if A.row_num() != A.col_num():#判断矩阵行是否等于列,若不等于无解
 93         return None
 94 
 95     n = A.row_num() # TODO:A.row_num 无括号代表方法,类型为method   A.row_num() 有括号代表具体的返回值
 96     print(n,type(n))
 97     ls = LinearSystem(A, Matrix.identity(n))#实例化一个线性系统(创建一个增广矩阵)
 98     if not ls.gauss_jordan_elimination(): #判断是否有逆矩阵(是否有解)
 99         return None
100 
101     invA = [[row[i] for i in range(n, n*n)] for row in ls.Ab] #将右侧的单位矩阵拼接到矩阵中
102 
103     return Matrix(invA)
104 
105 
106 #求矩阵的秩(主元数量)
107 def rank(A):
108 
109     ls = LinearSystem(A,None) #声明一个矩阵A
110     ls.gauss_jordan_elimination() #将矩阵进行高斯消元
111 
112     zero = Vector.zero(A.col_num())      #创建零向量(维度为该矩阵的列数即可,每一行的元素个数)
113     return sum([row != zero for row in ls.Ab])  #判断有多少非零行  (不等指的是向量间是否不等)

3.文件 main_diag.py 编写代码:

 1 import numpy as np
 2 from numpy.linalg import eig, inv # eig:特征值、特征向量  inv:矩阵的逆
 3 from playLA.LinearSystem import rank # 矩阵的秩(主元数量)
 4 from playLA.Matrix import Matrix
 5 
 6 #矩阵的对角化
 7 def diagonalize(A):
 8 
 9     assert A.ndim == 2 #判断A的维度为2
10     assert A.shape[0] == A.shape[1] #判断矩阵A的长等于宽(是否为方阵)
11 
12     eigenvalues, eigenvectors = eig(A)#求取矩阵的特征值与特征向量
13 
14     P = eigenvectors            #特征向量
15     if rank(Matrix(P.tolist())) != A.shape[0]:# 判断矩阵是否满秩(满秩矩阵可逆,不满秩则矩阵不可逆)
16         print("Matrix can not be diagonalized")#矩阵不能对角化
17         return None, None, None
18 
19     D = np.diag(eigenvalues)    #将特征值放入矩阵的对角线上
20     Pinv = inv(P)               #特征向量的逆
21 
22 
23     return P, D, Pinv
24 
25 
26 if __name__ == "__main__":
27 
28     A1 = np.array([[4, -2],
29                    [1, 1]])
30     P1, D1, Pinv1 = diagonalize(A1)
31     print(P1)
32     print(D1)
33     print(Pinv1)
34     print(P1.dot(D1).dot(Pinv1))
35 
36     A2 = np.array([[3, 1],
37                    [0, 3]])
38     P2, D2, Pinv2 = diagonalize(A2)
39     print(P2)
40     print(D2)
41     print(Pinv2)

4.文件 main_diag.py 运行结果:

 1 /Users/liuxiaoming/PycharmProjects/LinearAlgebra/venv/bin/python /Applications/PyCharm.app/Contents/plugins/python/helpers/pydev/pydevconsole.py --mode=client --port=63553
 2 import sys; print('Python %s on %s' % (sys.version, sys.platform))
 3 sys.path.extend(['/Users/liuxiaoming/PycharmProjects/LinearAlgebra'])
 4 PyDev console: starting.
 5 Python 3.8.2 (v3.8.2:7b3ab5921f, Feb 24 2020, 17:52:18) 
 6 [Clang 6.0 (clang-600.0.57)] on darwin
 7 runfile('/Users/liuxiaoming/PycharmProjects/LinearAlgebra/main_diag.py', wdir='/Users/liuxiaoming/PycharmProjects/LinearAlgebra')
 8 [[0.89442719 0.70710678]
 9  [0.4472136  0.70710678]]
10 [[3. 0.]
11  [0. 2.]]
12 [[ 2.23606798 -2.23606798]
13  [-1.41421356  2.82842712]]
14 [[ 4. -2.]
15  [ 1.  1.]]
16 Matrix can not be diagonalized
17 None
18 None
19 None


  • 矩阵对角化的应用:求解矩阵的幂和动态系统

 

 

 

 

 

 

 

 

 

 

 

posted @ 2020-09-04 00:48  霜井  阅读(568)  评论(0编辑  收藏  举报