这方面的总结一直都有想写,我们先从矩阵的转置和逆谈起。本篇内容整理自网页。
矩阵的转置和逆
给出这部分叙事的主角,矩阵A和矩阵B
A
=
[
1
2
3
4
]
B
=
[
1
2
3
4
5
6
]
A= \begin{bmatrix}1 &2 \\ 3&4 \end{bmatrix} \ \ \ \ \ B= \begin{bmatrix}1 &2 & 3\\ 4&5 &6 \end{bmatrix}
A=[1324] B=[142536]
矩阵的创建
在Python中借助Numpy的array对象就可以创建一个二维数组(即矩阵)。
>>> import numpy as np
>>> A = np.array([[1,2],[3,4]])#python用numpy中的array创建矩阵print(A)
>>> print(A)
[[1 2]
[3 4]]
>>> B = np.array([[1,2,3],[4,5,6]])
>>> print(B)
[[1 2 3]
[4 5 6]]
在matlab中这个创建过程更加容易,用逗号或空格作为列的分隔,用分号作为行的分隔。
>> A = [1,2;3,4]
A =
1 2
3 4
>> B = [1 2 3;4 5 6]
B =
1 2 3
4 5 6
矩阵的转置
矩阵的转置就是围绕主对角线方向做对称,或者说是将矩阵元素的行下标和列下标进行互换。
A
T
=
[
1
3
2
4
]
B
T
=
[
1
4
2
5
3
6
]
A^{T}= \begin{bmatrix}1 &3 \\ 2&4 \end{bmatrix} \ \ \ \ \ B^{T}= \begin{bmatrix}1 &4 \\ 2&5 \\ 3&6 \end{bmatrix}
AT=[1234] BT=⎣
⎡123456⎦
⎤
Numpy中提供了transpose函数实现转置。
>>> At = np.transpose(A)
>>> print(At)
[[1 3]
[2 4]]
>>> Bt = np.transpose(B)
>>> print(Bt)
[[1 4]
[2 5]
[3 6]]
matlab中直接用一撇就可以实现转置(默认实现共轭转置)。
>> At = A'
At =
1 3
2 4
>> Bt = B'
Bt =
1 4
2 5
3 6
矩阵的逆
跟矩阵的转置对所有矩阵都有效不同,矩阵的逆首先针对的对象是方阵。对于方阵而言,这几个概念是等价的:
可逆矩阵↔矩阵满秩↔通过有限次初等行变换能转化为单位矩阵↔非奇异矩阵↔行列式不为0
从定义看,逆矩阵是指与原矩阵做矩阵乘法后结果将为单位矩阵,即:
A
A
−
1
=
A
−
1
A
=
E
AA^{-1}=A^{-1}A=E
AA−1=A−1A=E
增广矩阵求解逆矩阵
手算矩阵的逆,我们一般有三种方法,即待定系数法、伴随矩阵法和初等变换法。由于可逆矩阵“通过有限次初等行变换能化为单位矩阵”的性质,所以我们往往利用增广矩阵求解一般性的矩阵的逆。
以A为例, 容易计算A的行列式为-2,不为0,矩阵是可逆的,下面展现用增广矩阵求解A的逆矩阵的步骤。
A
=
[
1
2
∣
1
0
3
4
∣
0
1
]
A= \begin{bmatrix}1 &2 & | & 1 & 0 \\ 3&4 & | & 0 &1 \end{bmatrix}
A=[1324∣∣1001]
容易看出,先将第二行减去第一行乘以3:
A
⇒
[
1
2
∣
1
0
0
−
2
∣
−
3
1
]
A\Rightarrow \begin{bmatrix}1 &2 & | & 1 & 0 \\ 0&-2 & | & -3 &1 \end{bmatrix}
A⇒[102−2∣∣1−301]
然后,第二行加回第一行:
A
⇒
[
1
0
∣
−
2
1
0
−
2
∣
−
3
1
]
A\Rightarrow \begin{bmatrix}1 &0 & | & -2 & 1 \\ 0&-2 & | & -3 &1 \end{bmatrix}
A⇒[100−2∣∣−2−311]
最后,第二行乘以负二分之一:
A
⇒
[
1
0
∣
−
2
1
0
1
∣
3
2
−
1
2
]
A\Rightarrow \begin{bmatrix}1 &0 & | & -2 & 1 \\ 0&1 & | & \frac{3}{2} &-\frac{1}{2} \end{bmatrix}
A⇒[1001∣∣−2231−21]
于是有A的逆矩阵为
A
−
1
=
[
−
2
1
3
2
−
1
2
]
A^{-1}= \begin{bmatrix} -2 & 1 \\ \frac{3}{2} &-\frac{1}{2} \end{bmatrix}
A−1=[−2231−21]
容易看出
A
A
−
1
=
E
AA^{-1} = E
AA−1=E,所求逆矩阵确实是正确的。
inv()函数求解逆矩阵
Numpy中线性代数库linalg提供了inv()函数来实现非奇异矩阵的逆矩阵求解。
>>> Ai = np.linalg.inv(A)
>>> print(Ai)
[[-2. 1. ]
[ 1.5 -0.5]]
matlab中也提供了相似的函数inv()。
>> Ai = inv(A)
Ai =
-2.0000 1.0000
1.5000 -0.5000
伪逆
显然非奇异矩阵是少数,那么对于奇异矩阵和非方阵而言,就不存在其逆矩阵,但我们能引入伪逆矩阵作为逆矩阵的广义形式。数学定义如下:
如果存在一个与A的转置矩阵A’ 同型的矩阵X,并且满足:AXA=A,XAX=X.此时,称矩阵X为矩阵A的伪逆,也称为广义逆矩阵。
容易验证逆矩阵是广义逆矩阵的特殊情形,即
A
A
−
1
A
=
E
A
=
A
,
A
−
1
A
A
−
1
=
E
A
−
1
=
A
−
1
,
其中
X
=
A
−
1
AA^{-1}A=EA=A , \ \ \ A^{-1}AA^{-1}=EA^{-1}=A^{-1} ,其中X = A^{-1}
AA−1A=EA=A, A−1AA−1=EA−1=A−1,其中X=A−1
满足 A L A = E A^{L}A = E ALA=E,但不满足 A A L = E AA^{L}=E AAL=E 的矩阵 A L A^{L} AL称为矩阵A的左逆矩阵。类似的,满足 A A R = E A A^{R}= E AAR=E,但不满足 A R A = E A^{R}A=E ARA=E 的矩阵 A R A^{R} AR称为矩阵A的右逆矩阵。我们分三种情况讨论(看得出来总是取秩更小的矩阵):
- 当m≥n时,列满秩,矩阵 A m × n A_{m\times n} Am×n有左逆矩阵, A n × m L = ( A T A ) − 1 A T A^{L}_{n\times m}=(A^{T} A)^{-1}A^{T} An×mL=(ATA)−1AT
- 当n≥m时,行满秩,矩阵 A m × n A_{m\times n} Am×n有右逆矩阵, A n × m R = A T ( A A T ) − 1 A^{R}_{n \times m}= A^{T}(AA^{T})^{-1} An×mR=AT(AAT)−1
- 当n =m时,
A
m
×
n
A_{m \times n}
Am×n的秩为
r
≤
m
=
n
r \le m = n
r≤m=n,对A进行奇异值分解
A
=
U
D
V
T
A = UDV^{T}
A=UDVT ,A的伪逆矩阵为
A
+
=
V
D
+
U
T
A^{+}=VD^{+}U^{T}
A+=VD+UT,其中
D
+
D^{+}
D+为奇异值矩阵的违逆矩阵,即主角线上的元素均取倒数。
(应该指出,奇异值分解这种方法具有一般性,留到写奇异值分解时探讨)
我们以处理比较简单的B为例,已知B有:
B
=
[
1
2
3
4
5
6
]
B
T
=
[
1
4
2
5
3
6
]
B= \begin{bmatrix}1 &2 & 3\\ 4&5 &6 \end{bmatrix} \ \ \ \ \ B^{T}= \begin{bmatrix}1 &4 \\ 2&5 \\ 3&6 \end{bmatrix}
B=[142536] BT=⎣
⎡123456⎦
⎤
于是
B
B
T
BB^{T}
BBT为
B
B
T
=
[
1
2
3
4
5
6
]
×
[
1
4
2
5
3
6
]
=
[
14
32
32
77
]
BB^{T}= \begin{bmatrix}1 &2 & 3\\ 4&5 &6 \end{bmatrix} × \begin{bmatrix}1 &4 \\ 2&5 \\ 3&6 \end{bmatrix} =\begin{bmatrix}14 &32 \\ 32 & 77 \end{bmatrix}
BBT=[142536]×⎣
⎡123456⎦
⎤=[14323277]
计算这个式子的行列式,容易发现其值为-54,逆矩阵是存在的。下面用行变换求解逆矩阵,先将(2,1)元素归零:
B
B
T
⇒
[
14
32
∣
1
0
0
3.857
∣
−
2.286
1
]
BB^{T} \Rightarrow \begin{bmatrix} 14 &32 & | & 1 & 0 \\ 0 & 3.857 & | & -2.286 & 1 \end{bmatrix}
BBT⇒[140323.857∣∣1−2.28601]
再将(1,2)元素归零:
B
B
T
⇒
[
14
0
∣
19.967
−
8.297
0
3.857
∣
−
2.286
1
]
BB^{T} \Rightarrow \begin{bmatrix} 14 &0 & | & 19.967 &-8.297 \\ 0 & 3.857 & | & -2.286 & 1 \end{bmatrix}
BBT⇒[14003.857∣∣19.967−2.286−8.2971]
最后将对角线元素归1:
B
B
T
⇒
[
1
0
∣
1.426
−
0.593
0
1
∣
−
0.593
0.259
]
BB^{T} \Rightarrow \begin{bmatrix} 1 &0 & | & 1.426 &-0.593 \\ 0 & 1 & | & -0.593 & 0.259 \end{bmatrix}
BBT⇒[1001∣∣1.426−0.593−0.5930.259]
于是就有B的右逆矩阵为(有一定误差):
B
R
=
B
T
(
B
B
T
)
−
1
=
[
1
4
2
5
3
6
]
×
[
1.426
−
0.593
−
0.593
0.259
]
=
[
−
0.946
−
0.443
−
0.113
0.109
−
0.720
−
0.225
]
B^{R}= B^{T}(BB^{T})^{-1}=\begin{bmatrix}1 &4 \\ 2&5 \\ 3&6 \end{bmatrix} \times \begin{bmatrix} 1.426 &-0.593 \\ -0.593 & 0.259 \end{bmatrix} = \begin{bmatrix} -0.946 &-0.443 \\ -0.113 & 0.109 \\ -0.720 &-0.225 \end{bmatrix}
BR=BT(BBT)−1=⎣
⎡123456⎦
⎤×[1.426−0.593−0.5930.259]=⎣
⎡−0.946−0.113−0.720−0.4430.109−0.225⎦
⎤
可以验证
B
R
B^{R}
BR是满足
B
B
R
=
E
B B^{R}= E
BBR=E,但不满足
B
R
B
=
E
B^{R}B=E
BRB=E 的矩阵,这也正是“右”的含义所在。
pinv()函数求解伪逆矩阵
相比于繁杂的对违逆情况的讨论,实际编程中求违逆只是一行代码的事。注意尽管逆矩阵是违逆矩阵的特例,但inv()具有比pinv()更高的求解效率,这在我们分别求解A和B的广义逆矩阵时就能体会得到。
Numpy中线性代数库linalg提供了pinv()函数来实现违逆矩阵求解。
>>> Bpi = np.linalg.pinv(B)
>>> print(Bpi)
[[-0.94444444 0.44444444]
[-0.11111111 0.11111111]
[ 0.72222222 -0.22222222]]
Matlab中也提供了相似的函数pinv()。
>> Bpi = pinv(B)
Bpi =
-0.9444 0.4444
-0.1111 0.1111
0.7222 -0.2222