矩阵的特征值与特征向量究竟意味着什么?
我的脑子比较笨, 很多东西一定要解释地特别直观, 否则我就是一头雾水. 尤其是矩阵的特征值与特征向量, 是线性代数中非常重要的概念. 我下决心要搞明白它到底有什么直观的含义.
    现在只考虑二阶方阵, 并且特征值都是实数. 即假设
    
    
     
      
       
        A 
=
(
4
−
2
1
1
)
,
         A =\left( \begin{matrix} 4 & -2 \\1 & 1\end{matrix} \right),
       
       
        
         
         
         
          A
         
         
         
         
          =
         
         
         
        
        
         
         
         
          
           
            (
           
          
          
           
            
             
              
               
                
                 
                 
                 
                  
                   4
                  
                 
                
                
                 
                 
                 
                  
                   1
                  
                 
                
               
               
                
               
              
              
               
                
                
               
              
             
            
            
            
            
            
            
             
              
               
                
                 
                 
                 
                  
                   −
                  
                  
                   2
                  
                 
                
                
                 
                 
                 
                  
                   1
                  
                 
                
               
               
                
               
              
              
               
                
                
               
              
             
            
           
          
          
           
            )
           
          
         
         
         
         
          ,
         
        
       
      
     
    
    
    经过计算, 矩阵
    
     
      
       A 
        A
      
      
       
        
        
        
         A
        
       
      
     
    
    的两个特征值分别为
    
     
      
       λ 
1
=
3
,
λ
2
=
2.
        \lambda_1 = 3, \lambda_2 = 2.
      
      
       
        
        
        
         
          λ
         
         
          
           
            
             
              
              
              
               
                1
               
              
             
            
            
             
            
           
           
            
             
             
            
           
          
         
        
        
        
        
         =
        
        
        
       
       
        
        
        
         3
        
        
         ,
        
        
        
        
         
          λ
         
         
          
           
            
             
              
              
              
               
                2
               
              
             
            
            
             
            
           
           
            
             
             
            
           
          
         
        
        
        
        
         =
        
        
        
       
       
        
        
        
         2
        
        
         .
        
       
      
     
    
    对应的特征向量分别为
    
     
      
       x 
1
=
(
0.89
,
0.45
)
T
,
x
2
=
(
0.71
,
0.71
)
T
.
        x_1 = (0.89, 0.45)^T, x_2=(0.71, 0.71)^T.
      
      
       
        
        
        
         
          x
         
         
          
           
            
             
              
              
              
               
                1
               
              
             
            
            
             
            
           
           
            
             
             
            
           
          
         
        
        
        
        
         =
        
        
        
       
       
        
        
        
         (
        
        
         0
        
        
         .
        
        
         8
        
        
         9
        
        
         ,
        
        
        
        
         0
        
        
         .
        
        
         4
        
        
         5
        
        
         
          )
         
         
          
           
            
             
              
              
              
               
                T
               
              
             
            
           
          
         
        
        
         ,
        
        
        
        
         
          x
         
         
          
           
            
             
              
              
              
               
                2
               
              
             
            
            
             
            
           
           
            
             
             
            
           
          
         
        
        
        
        
         =
        
        
        
       
       
        
        
        
         (
        
        
         0
        
        
         .
        
        
         7
        
        
         1
        
        
         ,
        
        
        
        
         0
        
        
         .
        
        
         7
        
        
         1
        
        
         
          )
         
         
          
           
            
             
              
              
              
               
                T
               
              
             
            
           
          
         
        
        
         .
        
       
      
     
    
   
    矩阵
    
     
      
       A 
        A
      
      
       
        
        
        
         A
        
       
      
     
    
    可以看成一个线性变换的算子, 即
    
     
      
       y 
=
A
x
        y=Ax
      
      
       
        
        
        
         y
        
        
        
        
         =
        
        
        
       
       
        
        
        
         A
        
        
         x
        
       
      
     
    
    , 即对变量
    
     
      
       x 
        x
      
      
       
        
        
        
         x
        
       
      
     
    
    施加一个线性变换得到新的变量
    
     
      
       y 
        y
      
      
       
        
        
        
         y
        
       
      
     
    
    . 现在先考虑一阶的矩阵
    
     
      
       A 
        A
      
      
       
        
        
        
         A
        
       
      
     
    
    , 也就是一个标量
    
     
      
       a 
        a
      
      
       
        
        
        
         a
        
       
      
     
    
    , 也是特殊的矩阵. 于是就得到了一元线性方程
    
     
      
       y 
=
a
x
        y=ax
      
      
       
        
        
        
         y
        
        
        
        
         =
        
        
        
       
       
        
        
        
         a
        
        
         x
        
       
      
     
    
    , 这简单得不能再简单了, 它的涵义也很清楚, 就是把数轴上(一维实数空间)的数变为原来的
    
     
      
       a 
        a
      
      
       
        
        
        
         a
        
       
      
     
    
    倍, 有一种把数轴往两边拉长的感觉. “矩阵”
    
     
      
       a 
        a
      
      
       
        
        
        
         a
        
       
      
     
    
    的特征值为
    
     
      
       a 
        a
      
      
       
        
        
        
         a
        
       
      
     
    
    , 数轴上每一个向量都是特征向量, 这是因为数轴上任意的一个 “向量” 经过线性变换, 方向都没有改变.
   
    一维空间的理解了, 那么对于二维空间也就好理解了. 回到上面的矩阵
    
     
      
       A 
        A
      
      
       
        
        
        
         A
        
       
      
     
    
    , 它二维空间上的线性算子, 它比一维情形复杂的地方在于它包含了两个维度之间的线性关系.
   
为了直观看一看这个线性变换的效果, 我画了个图来说明:
     
   
    图片最中心是原点, 为了图片简洁, 就没有画坐标轴. 绿线和蓝线分别是特征向量
    
     
      
       x 
1
        x_1
      
      
       
        
        
        
         
          x
         
         
          
           
            
             
              
              
              
               
                1
               
              
             
            
            
             
            
           
           
            
             
             
            
           
          
         
        
       
      
     
    
    和
    
     
      
       x 
2
        x_2
      
      
       
        
        
        
         
          x
         
         
          
           
            
             
              
              
              
               
                2
               
              
             
            
            
             
            
           
           
            
             
             
            
           
          
         
        
       
      
     
    
    所在的方向, 暗红色的点是采样的一些样本点
    
     
      
       x 
        x
      
      
       
        
        
        
         x
        
       
      
     
    
    , 绿色的点是经过矩阵
    
     
      
       A 
        A
      
      
       
        
        
        
         A
        
       
      
     
    
    作用后得到的新的向量, 黄色的是二者的连接线. 这里从一个圆上面采样(注意为了写代码方便, 没有进行均匀采样), 是因为二维空间中的所有向量都可以缩放到圆上, 这里只考察不同方向的向量. 从图中可以看到经过矩阵
    
     
      
       A 
        A
      
      
       
        
        
        
         A
        
       
      
     
    
    作用后, 把圆上的向量拉伸变形成了类似椭圆(有待于验证)的形状.
   
下面从一个矩形区域内采样, 看一看方向变化情况:
     
   
这里只看变换后的方向, 所有向量模长都进行归一化处理. 可以看到, 在特征向量方向上的向量没有改变方向, 其它方向的向量都改变了方向.
第一个图的代码(代码中的文件 1500.png 是一个宽高都为 1500 像素的空白图片, 用于画图):
from PIL import Image, ImageDraw
import numpy as np
from numpy.linalg import eig
img = Image.open("1500.png")
draw = ImageDraw.Draw(img) #建立绘图对象
width, height = img.size    #获取原始图像大小
A = np.array([[4, -2], 
              [1, 0.9]])
step = 80  # 每个多远采样一个点
p_range = 500  # 采样点范围
margin = width/2 
all_direction_norm = []
max_norm = 4050 # 提前计算好的最大长度
for i in range(-p_range, p_range, step):
    for j in range(-p_range, p_range, step):
        vector = np.array([i, j]) # 生成向量
        # 可选: 把vector变成单位向量, 再将模长放大50倍, 相当于在一个圆上采样
        vector = 50 * vector / (np.linalg.norm(vector) + 1e-3)
        #print(vector)
        #print(vector[0] + margin, vector[1] + margin)
        conversion = np.matmul(A, vector) # 变换后的向量
        direction_norm = (np.linalg.norm(conversion - vector) + 1e-3)
        all_direction_norm.append(direction_norm)
        direction = (conversion - vector) / direction_norm # 计算移动方向
        direction *= direction_norm # 保证像素长度大, 能画出图来
        # 画出线, 按照 direction_norm 的大小, 赋予由深到浅的颜色, 需要提前确定好最大的 direction_norm
        draw.line( ((vector[0] + margin, vector[1] + margin),
                    (vector[0] + int(direction[0] + margin), vector[1] + int(direction[1] + margin))),   fill = (200, 200, 50)) #画一条直线,(0, 0)到(width-1, height-1),fill指线的颜色
        # 把线的起点描成红色
        draw.line( ((vector[0] + margin,    vector[1] + margin),
                    (vector[0] + margin,    vector[1] + margin)),       fill = (150, int(direction_norm / max_norm * 255), 0))
        draw.line( ((vector[0] + margin,    vector[1] + margin),
                    (vector[0] + margin +1, vector[1] + margin)),       fill = (150, int(direction_norm / max_norm * 255), 0))
        draw.line( ((vector[0] + margin,    vector[1] + margin),
                    (vector[0] + margin+1,  vector[1] + margin+1)),     fill = (150, int(direction_norm / max_norm * 255), 0))
        draw.line( ((vector[0] + margin,    vector[1] + margin),
                    (vector[0] + margin,    vector[1] + margin+1)),     fill = (150, int(direction_norm / max_norm * 255), 0))
        draw.line( ((vector[0] + margin,    vector[1] + margin),
                    (vector[0] + margin-1,  vector[1] + margin)),       fill = (150, int(direction_norm / max_norm * 255), 0))
        draw.line( ((vector[0] + margin,    vector[1] + margin),
                    (vector[0] + margin-1,  vector[1] + margin+1)),     fill = (150, int(direction_norm / max_norm * 255), 0))
        draw.line( ((vector[0] + margin,    vector[1] + margin),
                    (vector[0] + margin-1,  vector[1] + margin-1)),     fill = (150, int(direction_norm / max_norm * 255), 0))
        draw.line( ((vector[0] + margin,    vector[1] + margin),
                    (vector[0] + margin,    vector[1] + margin-1)),     fill = (150, int(direction_norm / max_norm * 255), 0))
        draw.line( ((vector[0] + margin,    vector[1] + margin),
                    (vector[0] + margin+1,  vector[1] + margin-1)),     fill = (150, int(direction_norm / max_norm * 255), 0))
        # 把线的终点描成绿色
        draw.line( ((vector[0] + int(direction[0] + margin), vector[1] + int(direction[1] + margin)),
                    (vector[0] + int(direction[0] + margin), vector[1] + int(direction[1] + margin))),      fill = (0, 255, 0))
        draw.line( ((vector[0] + int(direction[0] + margin), vector[1] + int(direction[1] + margin)),
                    (vector[0] + int(direction[0] + margin) +1, vector[1] + int(direction[1] + margin))),   fill = (0, 255, 0))
        draw.line( ((vector[0] + int(direction[0] + margin), vector[1] + int(direction[1] + margin)),
                    (vector[0] + int(direction[0] + margin)+1, vector[1] + int(direction[1] + margin)+1)),  fill = (0, 255, 0))
        draw.line( ((vector[0] + int(direction[0] + margin), vector[1] + int(direction[1] + margin)),
                    (vector[0] + int(direction[0] + margin), vector[1] + int(direction[1] + margin)+1)),    fill = (0, 255, 0))
        draw.line( ((vector[0] + int(direction[0] + margin), vector[1] + int(direction[1] + margin)),
                    (vector[0] + int(direction[0] + margin)-1, vector[1] + int(direction[1] + margin))),    fill = (0, 255, 0))
        draw.line( ((vector[0] + int(direction[0] + margin), vector[1] + int(direction[1] + margin)),
                    (vector[0] + int(direction[0] + margin)-1, vector[1] + int(direction[1] + margin)+1)),  fill = (0, 255, 0))
        draw.line( ((vector[0] + int(direction[0] + margin), vector[1] + int(direction[1] + margin)),
                    (vector[0] + int(direction[0] + margin)-1, vector[1] + int(direction[1] + margin)-1)),  fill = (0, 255, 0))
        draw.line( ((vector[0] + int(direction[0] + margin), vector[1] + int(direction[1] + margin)),
                    (vector[0] + int(direction[0] + margin), vector[1] + int(direction[1] + margin)-1)),    fill = (0, 255, 0))
        draw.line( ((vector[0] + int(direction[0] + margin), vector[1] + int(direction[1] + margin)),
                    (vector[0] + int(direction[0] + margin)+1, vector[1] + int(direction[1] + margin)-1)),  fill = (0, 255, 0))
print("最大长度: ", max(all_direction_norm))
# 画特征向量
vals,  vecs = eig(A) # 特征分解,每一列是特征向量
a1 = vecs[0, 0]
a2 = vecs[1, 0]
b1 = vecs[0, 1]
b2 = vecs[1, 1]
# 画出两个特征向量
draw.line( ((margin,            margin), 
            (margin + a1 * 500, margin + a2 * 500)),
           fill = (0, 10, 255)) #画一条直线,(0, 0)到(width-1, height-1),fill指线的颜色
draw.line( ((margin,            margin), 
            (margin + b1 * 500, margin + b2 * 500)),
           fill = (0, 255, 10)) #画一条直线,(0, 0)到(width-1, height-1),fill指线的颜色
# 画出紫色中心点
draw.line(((margin, margin), (margin, margin)), fill = (255, 0, 255))#画一条直线,(0, 0)到(width-1, height-1),fill指线的颜色
img.save("result.png")#保存新图像
print("特征值:", vals)
print("特征向量:", vecs)
 
