矩阵变换的直观展示

通过代码展示矩阵变换

Posted by Xion on September 26, 2019      views:

矩阵变换

$Ax=y$

矩阵变换有多种解读:

变换

  • 向量x经过矩阵A的变换,变成了向量y

映射

  • 在坐标系A的度量下得到的结果为x,在标准坐标系下度量的结果为y
import numpy as np
import matplotlib.pyplot as plt
import time
import matplotlib.ticker as ticker
from mpl_toolkits.mplot3d import Axes3D
import mpl_toolkits.axisartist as axisartist

def show_change(A,show_eig = False):
    lines=np.array( [
        [[0,0,0],[0,0,1]],
        [[0,0,0],[0,1,0]],
        [[0,0,0],[1,0,0]],
        
        [[1,0,0],[1,0,1]],
        [[1,0,0],[1,1,0]],
        
        [[0,1,0],[0,1,1]],
        [[0,1,0],[1,1,0]],
        
        [[0,0,1],[0,1,1]],
        [[0,0,1],[1,0,1]],
        
        [[0,0,1],[0,1,1]],
        [[0,0,1],[0,1,1]],
        
        [[1,1,1],[1,1,0]],
        [[1,1,1],[1,0,1]],
        [[1,1,1],[0,1,1]],
    ])
    
    
    
    %matplotlib notebook
    fig = plt.figure()
    
    ax = Axes3D(fig,
                azim=23,
               )
    o = np.array([0,0,0])
    
    x =np.dot(np.array([1,0,0]),A)
    y =np.dot(np.array([0,1,0]) ,A)
    z =np.dot(np.array([0,0,1]) ,A)
    
    length = 1.2
    xs = [l[0] for l in lines]
    ys = [l[1] for l in lines]
    for l in lines:
        ax.plot( *zip(l[0],l[1]),color='c',ls='-.')
    
    for l in lines:
        s1 = np.dot(A,l[0])
        s2 = np.dot(A,l[1])
        ax.plot( *zip(s1,s2),color='r',ls='--')
    
    size = (-1,2)
    ax.set_xlim3d(*size)
    ax.set_ylim3d(*size)
    ax.set_zlim3d(*size)
    ax.set_xlabel('x')
    ax.set_ylabel('y')
    ax.set_zlabel('z')
    if show_eig:
        a,b = np.linalg.eig(A)
        o = [0,0,0]
        ax.plot(*zip(o,b[:,0]),color='b',ls='-',lw=2)
        ax.plot(*zip(o,b[:,1]),color='b',ls='-',lw=2)
        ax.plot(*zip(o,b[:,2]),color='b',ls='-',lw=2)
        
        new_b = np.dot(A,b)
        
        ax.plot(*zip(o,new_b[:,0]),color='y',ls='-.',lw=1)
        ax.plot(*zip(o,new_b[:,1]),color='y',ls='-.',lw=1)
        ax.plot(*zip(o,new_b[:,2]),color='y',ls='-.',lw=1)
        
        print('特征值:\n%s \n特征向量:\n%s' %(a,b))
     
    
    
A = np.array(
    [[1,0,0],
     [0,1,0],
     [0,0,1]]
)
show_change(A)
<IPython.core.display.Javascript object>

典型的对角矩阵

  • 沿着坐标轴的伸缩
  • 沿着y轴压缩0.5
  • 沿着z轴增长2 倍
  • 因此立方体的大小变成了 1 * 0.5 * 2 = 1。它是对角线的乘积,也就是det A
A = np.array([[1,0,0]
             ,[0,.5,0],
              [0,0,2]])

show_change(A)
[[1.  0.  0. ]
 [0.  0.5 0. ]
 [0.  0.  2. ]].[1 1 1]=[1.  0.5 2. ]



<IPython.core.display.Javascript object>

如果对角线元素中有0

  • x轴方向直接被压扁
  • 因此立方体的大小变成了 0,det A = 0
A = np.array([[0,0,0],[0,.5,0],[0,0,2]])

show_change(A)
[[0.  0.  0. ]
 [0.  0.5 0. ]
 [0.  0.  2. ]].[1 1 1]=[0.  0.5 2. ]



<IPython.core.display.Javascript object>

如果对角线元素中有负数

  • y 轴上线颠倒
  • det A < 0
A = np.array([[1,0,0],[0,-.5,0],[0,0,2]])

show_change(A)
[[ 1.   0.   0. ]
 [ 0.  -0.5  0. ]
 [ 0.   0.   2. ]].[1 1 1]=[ 1.  -0.5  2. ]



<IPython.core.display.Javascript object>

非对角矩阵

  • 发生了倾斜
  • 平行关系保持不变
  • 空间中的某些向量没有发生旋转而是只发生了伸缩,在图中用蓝色表示的向量经过A的变换后称为了黄色的向量。 这个压缩率就是特征值。
A = np.array([[2,-0.5,-0.5],[-0.5,2,-0.5],[-0.5,-0.5,2]])

show_change(A,show_eig=True)


<IPython.core.display.Javascript object>

特征值:
[2.5 1.  2.5] 
特征向量:
[[ 0.81649658 -0.57735027  0.47168785]
 [-0.40824829 -0.57735027 -0.81302061]
 [-0.40824829 -0.57735027  0.34133277]]

观察秩和可逆性

  • 下面的矩阵把原本的正方体变化为了一个平面,体积为零因此 detA = 0
  • 维度从三维降低为两维,因此rand A = 2
  • 有一个特征向量被变换为了一个点,因次它对应的特征值为0
  • 由于被压缩到了一个平面上,无法推测 A 的逆变化,因此 A 的逆矩阵不存在
x = np.array([1,1,1])
A = np.array([[2,2,2],[1,1,1],[1,1,2]])

y=np.dot(A,x)
print('{}.{}={}'.format(A,x,y))

a,b = np.linalg.eig(A)

print('特征值: %s' %a)
print('特征向量:%s' %b)
show_change(A,show_eig=True)


[[2 2 2]
 [1 1 1]
 [1 1 2]].[1 1 1]=[6 3 4]
特征值: [ 4.30277564e+00 -3.10974594e-16  6.97224362e-01]
特征向量:[[-7.72827507e-01 -7.07106781e-01 -6.23093003e-01]
 [-3.86413754e-01  7.07106781e-01 -3.11546502e-01]
 [-5.03410424e-01 -8.00981857e-17  7.17421694e-01]]



<IPython.core.display.Javascript object>

特征值:
[ 4.30277564e+00 -3.10974594e-16  6.97224362e-01] 
特征向量:
[[-7.72827507e-01 -7.07106781e-01 -6.23093003e-01]
 [-3.86413754e-01  7.07106781e-01 -3.11546502e-01]
 [-5.03410424e-01 -8.00981857e-17  7.17421694e-01]]

观察行列的交替性质

对比下面两个结果可以看出,如果交换行列式的列或者行,那么空间发生了翻转,但是体积不变,因此

det(A) = -det(A_hat)

A = np.array(
    [
       [1,0,0],
       [0,1,0],
        [0,0,0],
    ])


show_change(A,show_eig=True)

<IPython.core.display.Javascript object>

特征值:
[1. 1. 0.] 
特征向量:
[[1. 0. 0.]
 [0. 1. 0.]
 [0. 0. 1.]]
A_hat = np.array(
    [
       [0,1,0],
       [1,0,0],
        [0,0,0],
    ])


show_change(A_hat,show_eig=True)

<IPython.core.display.Javascript object>

特征值:
[ 1. -1.  0.] 
特征向量:
[[ 0.70710678 -0.70710678  0.        ]
 [ 0.70710678  0.70710678  0.        ]
 [ 0.          0.          1.        ]]