前言

本文将简单总结线性代数的基本知识点。同时理论结合实际,使用 Python 来进行实践。如果需要跟着进行编程实践,请先确保下列环境已安装:

  • Python - 编程实践所使用的语言;
  • Numpy - Python 的数值计算库。

矩阵

矩阵(Matrix)是人为约定的一种数据的表示方法,在图像处理、人工智能等领域,使用矩阵来表示和处理数据非常常见。一个矩阵的举例:

\[\mathbf{A}_{2 \times 3}=\begin{bmatrix} 5 & 2 & 7 \\ 1 & 3 & 4 \end{bmatrix}\]

其中,矩阵 \(\mathbf{A}\) 的下标 \(2 \times 3\) 表示 \(\mathbf{A}\) 是一个 2 行 3 列的矩阵。类似的,另一个示例:

\[\mathbf{ B }_{ 4 \times 4 }=\begin{bmatrix} 5 & 2 & 7 & 6 \\ 1 & 3 & 4 & 2 \\ 7 & -1 & 9 & 0 \\ 8 & 2 & -2 & 3 \end{bmatrix}\]

再看回矩阵 \(\mathbf{A}\) ,如果要表示第 2 行的第 2 个元素 3 ,可以使用 \(\mathbf{A}[2, 2]\) 或 \(a_{2,2}\)。

Python 的 Numpy 库提供了 ndarray 类用于存储高维数组及普通的数组运算,另外提供 matrix 类用来支持矩阵运算。使用 Python 创建矩阵很简单:

1
2
3
import numpy as np
a = np.matrix('5 2 7;1 3 4')
b = np.matrix('5 2 7 6;1 3 4 2;8 2 -2 3')

也可以用下面这种形式:

1
2
3
import numpy as np
a = np.matrix([[5,2,7],[1,3,4]])
b = np.matrix([[5,2,7,6],[1,3,4,2],[8,2,-2,3]])

两种形式完全等效。但第一种更简明直观,不容易犯错。因此推荐第一种方式。

要把一个 matrix 对象转换为 ndarray 对象,可以直接用 getA() 方法。而把 ndarray 对象转成 matrix 对象可以用 asmatrix() 方法。

1
2
3
4
5
6
7
8
9
10
11
12
>>> b = a.getA()
>>> print b
[[5 2 7]
[1 3 4]]
>>> type(b)
<type 'numpy.ndarray'>
>>> c = np.asmatrix(b)
>>> print c
[[5 2 7]
[1 3 4]]
>>> type(c)
<class 'numpy.matrixlib.defmatrix.matrix'>

要取出矩阵中的某个值,可以使用类似数组的下标运算符。但要注意的是,计算机是以 0 开始计数的。例如,要取出 \(\mathbf{A}[2,2]\) ,应该使用:

1
2
3
>>> a[1,1]
a[1,1]
3

基本运算

矩阵加法的定义非常符合直觉。假设有 \(\mathbf{ A }_{ 3 \times 3 }=\begin{bmatrix} 1 & 0 & 1 \\ 1 & 2 & 1 \\ 2 & 1 & 1 \end{bmatrix}\) , \(\mathbf{ B }_{ 3 \times 3 }=\begin{bmatrix} 2 & 1 & -1 \\ 0 & -1 & 2 \\ 2 & -1 & 0 \end{bmatrix}\) ,则:

\[\mathbf{A}+\mathbf{B} = \begin{bmatrix} 1 & 0 & 1 \\ 1 & 2 & 1 \\ 2 & 1 & 1 \end{bmatrix} + \begin{bmatrix} 2 & 1 & -1 \\ 0 & -1 & 2 \\ 2 & -1 & 0 \end{bmatrix} = \begin{bmatrix} 1+2 & 0+1 & 1+(-1) \\ 1+ 0 & 2+(-1) & 1+2 \\ 2+2 & 1+(-1) & 1+0 \end{bmatrix} = \begin{bmatrix} 3 & 1 & 0 \\ 1 & 1 & 3 \\ 4 & 0 & 1 \end{bmatrix} \]

要注意两个矩阵的行数和列数必须相同,否则无定义。

Python 示例:

1
2
3
4
5
6
7
8
9
>>> a = np.matrix('1 0 1;1 2 1;2 1 1')
a = np.matrix('1 0 1;1 2 1;2 1 1')
>>> b = np.matrix('2 1 -1;0 -1 2;2 -1 0')
b = np.matrix('2 1 -1;0 -1 2;2 -1 0')
>>> a + b
a + b
matrix([[3, 1, 0],
[1, 1, 3],
[4, 0, 1]])

很容易看出,矩阵的加法满足交换律和结合律,即 \(\mathbf{A} + \mathbf{B} = \mathbf{B} + \mathbf{A}\), \((\mathbf{A} + \mathbf{B}) + \mathbf{C} = \mathbf{A} + (\mathbf{B} + \mathbf{C})\)。

矩阵减法也和加法一样简单。对于上面给出的 \(\mathbf{A}\) 和 \(\mathbf{B}\),有:

\[\mathbf{A}-\mathbf{B}=\begin{bmatrix} 1 & 0 & 1 \\ 1 & 2 & 1 \\ 2 & 1 & 1 \end{bmatrix}-\begin{bmatrix} 2 & 1 & -1 \\ 0 & -1 & 2 \\ 2 & -1 & 0 \end{bmatrix}=\begin{bmatrix} 1-2 & 0-1 & 1-(-1) \\ 1-0 & 2-(-1) & 1-2 \\ 2-2 & 1-(-1) & 1-0 \end{bmatrix}=\begin{bmatrix} -1 & -1 & 2 \\ 1 & 3 & -1 \\ 0 & 2 & 1 \end{bmatrix}\]

同样,相减的两个矩阵行数和列数必须完全相同,否则无定义。

Python 示例:

1
2
3
4
5
>>> a - b
a - b
matrix([[-1, -1, 2],
[ 1, 3, -1],
[ 0, 2, 1]])

矩阵乘法的定义是 \(\mathbf{A}_{i \times j}\) 矩阵的每一行的元素分别与 $\mathbf{B}_{j \times k} $ 矩阵的每一列的元素两两相乘并相加,从而得到一个新的矩阵 \(\mathbf{C}_{i \times k}\) 。两个矩阵能相乘的充分必要条件是第一个矩阵的列数与第二个矩阵的行数相等,否则无定义。例如,对于上面给出的 \(\mathbf{A}\) 和 \(\mathbf{B}\),有:

\[\begin {aligned} \mathbf{A} \times \mathbf{B} &=\begin{bmatrix} 1 & 0 & 1 \\ 1 & 2 & 1 \\ 2 & 1 & 1 \end{bmatrix}\times \begin{bmatrix} 2 & 1 & -1 \\ 0 & -1 & 2 \\ 2 & -1 & 0 \end{bmatrix} \\\ &=\begin{bmatrix} 1\cdot 2+0\cdot 0+1\cdot 2 & 1\cdot 1+0\cdot (-1)+1\cdot (-1) & 1\cdot (-1)+0\cdot 2+1\cdot 0 \\ 1\cdot 2+2\cdot 0+1\cdot 2 & 1\cdot 1+2\cdot (-1)+1\cdot (-1) & 1\cdot (-1)+2\cdot 2+1\cdot 0 \\ 2\cdot 2+1\cdot 0+1\cdot 2 & 2\cdot 1+1\cdot (-1)+1\cdot (-1) & 2\cdot (-1)+1\cdot 2+1\cdot 0 \end{bmatrix}\\\ &=\begin{bmatrix} 4 & 0 & -1 \\ 4 & -2 & 3 \\ 6 & 0 & 0 \end{bmatrix} \end {aligned} \]

再举一个行列数不同的例子, 假设有 \(\mathbf{C}_{2 \times 3} = \begin{bmatrix} 5 & 7 & 2 \\ 4 & 3 & 1 \end{bmatrix}\) 和 \(\mathbf{D}_{3 \times 1} = \begin{bmatrix} 1 \\ 5 \\ 6 \end{bmatrix}\),则可以得出:

\[ \mathbf{C}\times \mathbf{D} = \begin{bmatrix} 5 & 7 & 2 \\ 4 & 3 & 1 \end{bmatrix}\times \begin{bmatrix} 1 \\ 5 \\ 6 \end{bmatrix} =\begin{bmatrix} 5 \cdot 1+ 7 \cdot 5+ 2\cdot 6 \\ 4\cdot 1+3\cdot 5+1\cdot 6 \end{bmatrix} =\begin{bmatrix} 52 \\ 25 \end{bmatrix} \]

与初等代数的乘法不同,矩阵的乘法并不满足交换律,即 \(\mathbf{A} \times \mathbf{B} \ne \mathbf{B} \times \mathbf{A}\)。但满足分配律,即 \((\mathbf{A} \times \mathbf{B}) \times \mathbf{C} = \mathbf{A} \times (\mathbf{B} \times \mathbf{C})\)。

再介绍两个特殊的矩阵:

  1. 单元矩阵 \(\mathbf{I}\) 。它的特点是行数列数相等,且在对角线上值为 1,其他地方值为 0 。它的一个特性是与其他矩阵相乘都等于那个矩阵本身。一个 \(3\times 3\) 的单元矩阵示例:\[\mathbf{I}_{3 \times 3} = \begin{bmatrix} 1 & 0 & 0 \\ 0 & 1 & 0 \\ 0 & 0 & 1 \end{bmatrix}\]
  2. 零矩阵。顾名思义就是全部元素都是 0 的矩阵。零矩阵乘以任何矩阵都为零矩阵,与任何矩阵相加都等于那个矩阵。

Python 示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
>>> a * b
a * b
matrix([[ 4, 0, -1],
[ 4, -2, 3],
[ 6, 0, 0]])
>>> b * a
b * a
matrix([[ 1, 1, 2],
[ 3, 0, 1],
[ 1, -2, 1]])
>>> c = np.matrix('5 7 2;4 3 1')
c = np.matrix('5 7 2;4 3 1')
>>> d = np.matrix('1;5;6')
d = np.matrix('1;5;6')
>>> c*d
c*d
matrix([[52],
[25]])
>>> a * b * d
a * b * d
matrix([[-2],
[12],
[ 6]])
>>> a * (b * d)
a * (b * d)
matrix([[-2],
[12],
[ 6]])
>>> I = np.eye(3) # 创建一个3阶单元矩阵
I = np.eye(3)
>>> a * I
a * I
matrix([[1, 0, 1],
[1, 2, 1],
[2, 1, 1]])
>>> I * a
I * a
matrix([[1, 0, 1],
[1, 2, 1],
[2, 1, 1]])
>>> a * z
a * z
matrix([[0, 0, 0],
[0, 0, 0],
[0, 0, 0]])
>>> b * z
b * z
matrix([[0, 0, 0],
[0, 0, 0],
[0, 0, 0]])
>>> c * z
c * z
matrix([[0, 0, 0],
[0, 0, 0]])

注意上面创建单元矩阵用了 ‘eye’ 方法,它等同于下面的写法:

1
>>> I = np.matrix('1 0 0;0 1 0;0 0 1')

除(求逆)

矩阵并没有一个直接叫除法的操作。但有个与之相似的运算,叫做求逆运算。

矩阵 \(\mathbf{A}\) 的逆 \(\mathbf{A}^{-1}\) 被定义为一个与 \(\mathbf{A}\) 相乘后能得到一个单元矩阵的矩阵。即:\(\mathbf{A} \times \mathbf{A}^{-1} = \mathbf{I}\)。求逆这个操作本身是可逆的,一个矩阵的逆的逆也是这个矩阵本身。因此 \(\mathbf{A}^{-1} \times \mathbf{A} = \mathbf{I}\)。根据这个特点我们可以推断出能求逆的矩阵,其行数和列数也必然相同。

为什么说这个求逆操作很像除等代数的除法呢?因为矩阵的逆很像数的倒数,一个数乘以它的倒数等于 1。而拿倒数与其他数相乘,就相当于被其他数除。

矩阵的求逆有很多种方法。常见的有伴随阵法、初等变换法、分块矩阵求逆法等[1]

伴随阵法

定理 \(n\) 阶矩阵 \(\mathbf{A}=\begin{bmatrix}a_{ij}\end{bmatrix}\) 为可逆的充分必要条件是 \(\mathbf{A}\) 非奇异。且

\[\mathbf{A}^{-1}=\frac{1}{|\mathbf{A}|}\begin{bmatrix}A_{11} & A_{21} & \ldots & A_{n1} \\ A_{12} & A_{22} & \ldots & A_{n2} \\ \ldots & \ldots & \ldots & \ldots \\ A_{1n} & A_{2n} & \ldots & A_{nn} \end{bmatrix}\]

其中 \(\mathbf{A}_{ij}\) 是 \(|\mathbf{A}|\) 中元素 \(a_{ij}\) 的代数余子式。

矩阵 \(\begin{bmatrix}A_{11} & A_{21} & \ldots & A_{n1} \\ A_{12} & A_{22} & \ldots & A_{n2} \\ \ldots & \ldots & \ldots & \ldots \\ A_{1n} & A_{2n} & \ldots & A_{nn} \end{bmatrix}\) 称为矩阵 \(\mathbf{A}\) 的伴随矩阵,记作 \(\mathbf{A}^{*}\) ,于是有 \(\mathbf{A}^{-1}=\frac{1}{|\mathbf{A}|}\mathbf{A}^{*}\)。

对于二阶矩阵,使用伴随阵法比较简单。

假定一个矩阵 \(\mathbf{M}=\begin{bmatrix} a & b \\ c & d \end{bmatrix}\),则

\[\mathbf{M}^{-1}=\frac{1}{|\mathbf{M}|}\begin{bmatrix} d & -b \\ -c & a \end{bmatrix}\]

,其中 \(|\mathbf{M}|\) 称为矩阵 \(\mathbf{M}\) 的行列式:

\[|\mathbf{M}| = ad - bc\]

,而 \(\begin{bmatrix} d & -b \\ -c & a \end{bmatrix}\) 就是矩阵 \(\mathbf{M}\) 的伴随矩阵。

例如,对于矩阵 \(A = \begin{bmatrix} 5 & 7 \\ 3 & 2 \end{bmatrix}\),那么有:

\[|\mathbf{A}|=5\cdot 2-7\cdot 3=-11\]

,则

\[\mathbf{A}^{ -1 }=\frac { 1 }{ -11 } \begin{bmatrix} 2 & -7 \\ -3 & 5 \end{bmatrix}=\begin{bmatrix} -\frac { 2 }{ 11 } & \frac { 7 }{ 11 } \\ \frac { 3 }{ 11 } & -\frac { 5 }{ 11 } \end{bmatrix}\]

验证一下 \(\mathbf{A} \times \mathbf{A}^{-1}\) 的值是否等于 \(\mathbf{I}\) ,有:

\[\mathbf{A}\times \mathbf{A}^{ -1 }=\begin{bmatrix} 5 & 7 \\ 3 & 2 \end{bmatrix}\times \begin{bmatrix} -\frac { 2 }{ 11 } & \frac { 7 }{ 11 } \\ \frac { 3 }{ 11 } & -\frac { 2 }{ 11 } \end{bmatrix}=\begin{bmatrix} 5\cdot \left( -\frac { 2 }{ 11 } \right) +7\cdot \frac { 3 }{ 11 } & 5\cdot \frac { 7 }{ 11 } +\left( -7\cdot \frac { 5 }{ 11 } \right) \\ 3\cdot \left( -\frac { 2 }{ 11 } \right) +2\cdot \frac { 3 }{ 11 } & 3\cdot \frac { 7 }{ 11 } +2\cdot \left( -\frac { 5 }{ 11 } \right) \end{bmatrix}=\begin{bmatrix} 1 & 0 \\ 0 & 1 \end{bmatrix} = \mathbf{I}\]

初等变换法

求元素为具体数字的矩阵的逆矩阵,常用初等变换法(又称为高斯·约当消去法)。用矩阵表示 $(\mathbf{A} \mathbf{I})\xrightarrow [ ]{ 初等变换 } (\mathbf{I} \mathbf{A}^{-1}) $ ,就是求逆矩阵的初等行变换法。\((\mathbf{A} \mathbf{I})\) 被称为矩阵 \(\mathbf{A}\) 的增广矩阵。

矩阵的初等行变换和初等列变换,统称矩阵的初等变换。下面的三种变换称为矩阵的初等行变换:

  1. 对调两行;
  2. 以数 \(k \ne 0\) 乘某一行的所有元素;
  3. 把某一行所有元素的 \(k\) 倍加到另一行对应的元素上去。

把上面定义中的“行”换成“列”,既得矩阵的初等列变换的定义。如果矩阵A经过有限次初等变换变成矩阵B,就称矩阵A与B等价。

三阶以上的伴随矩阵如果使用伴随阵法求逆,需要求9个或9个以上的代数余子式,以及一个三阶或三阶以上的行列式,过程比较繁琐。相比之下,使用初等变换就简单很多。

假定有三阶矩阵 \({ \mathbf{A} }_{ 3 \times 3 }=\begin{bmatrix} 1 & 0 & 1 \\ 1 & 2 & 1 \\ 2 & 1 & 1 \end{bmatrix}\) ,则:

\[ \begin{aligned} \begin{bmatrix}\mathbf{A} \mathbf{I}\end{bmatrix} & \rightarrow \begin{bmatrix} 1 & 0 & 1 & 1 & 0 & 0 \\ 1 & 2 & 1 & 0 & 1 & 0 \\ 2 & 1 & 1 & 0 & 0 & 1 \end{bmatrix} \rightarrow \begin{bmatrix} 1 & 0 & 1 & 1 & 0 & 0 \\ 0 & 2 & 0 & -1 & 1 & 0 \\ 2 & 1 & 1 & 0 & 0 & 1 \end{bmatrix} \rightarrow \begin{bmatrix} 1 & 0 & 1 & 1 & 0 & 0 \\ 0 & 1 & 0 & -0.5 & 0.5 & 0 \\ 2 & 1 & 1 & 0 & 0 & 1 \end{bmatrix}\\ & \rightarrow \begin{bmatrix} 1 & 0 & 1 & 1 & 0 & 0 \\ 0 & 1 & 0 & -0.5 & 0.5 & 0 \\ 1 & 1 & 0 & -1 & 0 & 1 \end{bmatrix} \rightarrow \begin{bmatrix} 1 & 0 & 1 & 1 & 0 & 0 \\ 0 & 1 & 0 & -0.5 & 0.5 & 0 \\ 1 & 0 & 0 & -0.5 & -0.5 & 1 \end{bmatrix} \rightarrow \begin{bmatrix} 0 & 0 & 1 & 1.5 & 0.5 & -1 \\ 0 & 1 & 0 & 0 & 0.5 & 0 \\ 1 & 0 & 0 & -0.5 & -0.5 & 1 \end{bmatrix}\\ &\rightarrow \begin{bmatrix} 1 & 0 & 0 & -0.5 & -0.5 & 1 \\ 0 & 1 & 0 & -0.5 & 0.5 & 0 \\ 0 & 0 & 1 & 1.5 & 0.5 & -1 \end{bmatrix} \end{aligned} \]

因此

\[\mathbf{A}^{-1}=\begin{bmatrix}-0.5 & -0.5 & 1 \\ -0.5 & 0.5 & 0 \\ 1.5 & 0.5 & -1\end{bmatrix}\]

奇异矩阵

要注意的是,矩阵并不一定都可逆的。从定义来看,只要矩阵 \(\mathbf{M}\) 的行列式 \(|\mathbf{M}|\) 为 0 ,则 \[\mathbf{M}^{-1}=\frac{1}{|\mathbf{M}|}\begin{bmatrix} d & -b \\ -c & a \end{bmatrix}\] 的值就无定义。我们把这种矩阵叫做 奇异矩阵

例如矩阵 \(\begin{bmatrix}0 & 0\\ 0 & 1\end{bmatrix}\) ,其行列式的值为 \(0 \cdot 1 - 0 \cdot 0 = 0\) ,因此无法求逆。

Python 求逆示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
>>> a = np.matrix('1 0 1; 1 2 1; 2 1 1')
a = np.matrix('1 0 1; 1 2 1; 2 1 1')
>>> a.I
a.I
matrix([[-0.5, -0.5, 1. ],
[-0.5, 0.5, 0. ],
[ 1.5, 0.5, -1. ]])
>>> a * a.I
a * a.I
matrix([[ 1., 0., 0.],
[ 0., 1., 0.],
[ 0., 0., 1.]]
>>> a.I * a
a.I * a
matrix([[ 1., 0., 0.],
[ 0., 1., 0.],
[ 0., 0., 1.]])
>>> f = np.matrix('0 1;0 0')
f = np.matrix('0 1;0 0')
>>> f.I
f.I
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "/Library/Python/2.7/site-packages/numpy/matrixlib/defmatrix.py", line 972, in getI
return asmatrix(func(self))
File "/Library/Python/2.7/site-packages/numpy/linalg/linalg.py", line 526, in inv
ainv = _umath_linalg.inv(a, signature=signature, extobj=extobj)
File "/Library/Python/2.7/site-packages/numpy/linalg/linalg.py", line 90, in _raise_linalgerror_singular
raise LinAlgError("Singular matrix")
numpy.linalg.linalg.LinAlgError: Singular matrix

矩阵的转置

矩阵 \(\underset{m\times n}{\mathbf{A}} = \begin{bmatrix}a_{11} & a_{12} & \ldots & a_{1n} \\ a_{21} & a_{22} & \ldots & a_{2n} \\ \ldots \\ a_{m1} & a_{m2} & \ldots & a_{mn}\end{bmatrix}\) 的转置定义为 \(\underset{n\times n}{A^{T}} = \begin{bmatrix}a_{11} & a_{21} & \ldots & a_{m1} \\ a_{12} & a_{22} & \ldots & a_{m2} \\ \ldots \\ a_{1n} & a_{2n} & \ldots & a_{mn}\end{bmatrix}\)

例如矩阵 \(\mathbf{A} = \begin{bmatrix} 2 & 4 \\ 1 & 3\end{bmatrix}\) 的转置矩阵就是 \(\mathbf{A}^T = \begin{bmatrix} 2 & 1 \\ 4 & 3\end{bmatrix}\);矩阵 \(\mathbf{B} = \begin{bmatrix} 1 & 2 & 3 \\ 4 & 5 & 6 \end{bmatrix}\) 的转置矩阵就是 \(\mathbf{B}^T = \begin{bmatrix} 1 & 4 \\ 2 & 5 \\ 3 & 6\end{bmatrix}\)。

Python 示例:

1
2
3
4
5
6
7
8
9
>>> a = np.matrix('2 4;1 3')
>>> a.T
matrix([[2, 1],
[4, 3]])
>>> b = np.matrix('1 2 3;4 5 6')
>>> b.T
matrix([[1, 4],
[2, 5],
[3, 6]])

矩阵的转置有一个性质:矩阵乘积的转置等于矩阵调换后分别做转置的乘积,即 \[(\mathbf{A}\cdot \mathbf{B})^T = \mathbf{B}^T\cdot \mathbf{A}^T\]

Python 示例:

1
2
3
4
5
6
7
8
>>> a = np.matrix('2 4;1 3')
>>> b = np.matrix('1 6;2 5')
>>> a*b
matrix([[10, 32],
[ 7, 21]])
>>> b.T*a.T
matrix([[10, 7],
[32, 21]])

应用举例

矩阵是一种非常通用的数据表示方法,只要能用矩阵来表示数据,就能够用矩阵的这套运算来解决问题。下面列举几种常见的数学问题,它们都能够使用矩阵的思路来解决。

求解方程组

例如一个二元方程组

\[\left\{ \begin{eqnarray} 3x+2y & = & 7 \\ -x+y & = & 1 \end{eqnarray} \right. \]

可以用矩阵表示成:

\[\begin{bmatrix} 3 & 2 \\ -1 & 1 \end{bmatrix} \begin{bmatrix} x \\ y \end{bmatrix} = \begin{bmatrix} 7\\ 1 \end{bmatrix} \]

设公式里的 \(\begin{bmatrix} 3 & 2 \\ -1 & 1\end{bmatrix}\) 为矩阵 \(A\),将等式两边左乘一个 \(A\) 的逆得到:

\[ \begin{aligned} A^{-1}A \begin{bmatrix} x \\ y \end{bmatrix} &= A^{-1} \begin{bmatrix} 7\\ 1 \end{bmatrix}\\\ &= \frac{1}{|A|}\begin{bmatrix}1 & -2 \\ 1 & 3\end{bmatrix} \begin{bmatrix} 7\\ 1 \end{bmatrix}\\\ &= \frac{1}{5}\begin{bmatrix}1 & -2 \\ 1 & 3\end{bmatrix} \begin{bmatrix} 7\\ 1 \end{bmatrix}\\\ &= \frac{1}{5}\begin{bmatrix}5 \\ 10\end{bmatrix} \end{aligned} \]

因此: $ \begin{bmatrix}x \\ y\end{bmatrix} = \begin{bmatrix}1 \\ 2\end{bmatrix} $

虽然这个例子给出的方法用于二元一次矩阵求解还不如直接用初中就学到的消元法,但矩阵的好处在于对于更高维的数据,比如有成百上千个未知数,这个解法依然有效。

在 Python 中,可以使用 Numpy 的线性代数算法库 linalg 提供的 solve 方法求解方程组。示例如下:

1
2
3
4
5
6
7
8
9
>>> a = np.matrix('3 2; -1 1')
>>> b = np.matrix('7; 1')
>>> x = np.linalg.solve(a, b)
>>> x
>>> matrix([[ 1.],
[ 2.]])
# 检查结果是否正确
>>> np.allclose(np.dot(a, x), b)
True

求向量组合

假设有向量 \(\vec { a } = \begin{bmatrix} 3 \\ -1 \end{bmatrix}\) ,\(\vec { b } = \begin{bmatrix} 2 \\ 1 \end{bmatrix}\) ,求二者如何组合成向量 \(\vec { c } = \begin{bmatrix} 7 \\ 1 \end{bmatrix}\) ?

如果用 \(x\) 和 \(y\) 分别表示两个向量的倍数,这个问题就同样可以用矩阵表示成:

\[\begin{bmatrix} 3 \\ -1 \end{bmatrix} x + \begin{bmatrix} 2 \\ 1 \end{bmatrix} y = \begin{bmatrix} 7\\ 1 \end{bmatrix} \]

这样就得到了一个和上一个问题完全同构的问题,使用相同解法解决得出 $ \begin{bmatrix}x \\ y\end{bmatrix} = \begin{bmatrix}1 \\ 2\end{bmatrix} $。

向量

向量是线性代数中的基本概念,也是机器学习的基础数据表示形式。例如计算机阅读文本的过程首先就会将文本分词,然后用向量表示[2]。这是因为向量很适合在高维空间中表达和处理。在机器学习中会接触到的诸如投影、降维的概念,都是在向量的基础上做的。

在 \(\mathbb{R}^{n}\) [3]空间中定义的向量 \(\vec{\mathbf{V}}\),可以用一个包含 n 个实数的有序集来表示,即 \(\vec{\mathbf{V}} = \begin{bmatrix}v_1 \\ v_2 \\ \ldots \\ v_n\end{bmatrix}\),这个有序集里的每个元素称为向量的 分量 。例如一个 \(\mathbb{R}^{2}\) 空间中的向量 \(\begin{bmatrix}2 \\ 1\end{bmatrix}\) ,有些地方也会用 \((2, 1)\) 或 \(<2, 1>\) 这样的形式来表示。

绘图表示这个变量:

向量的长度被定义为 \[\left\| \vec{\mathbf{v}} \right\| = \sqrt{v_{1}^{2} + v_{2}^{2} + \ldots + v_{n}^{2}}\],和我们以往所接触的距离公式一模一样。长度为 1 的向量称为 单位向量

基本运算

向量 \(\mathbf{a}\) 与向量 \(\mathbf{b}\) 的加法定义为:

\[ \mathbf{a} + \mathbf{b} = \begin{bmatrix} a_1 + b_1 \\ a_2 + b_2 \\ \ldots \\ a_n + b_n \end{bmatrix} \]

绘图示意向量 \(\mathbf{a} = \begin{bmatrix}-1 \\ 2\end{bmatrix}\) 与 \(\mathbf{b} = \begin{bmatrix}3 \\ 1\end{bmatrix}\) 的相加,值为 \(\begin{bmatrix}2 \\ 3\end{bmatrix}\) :

在 Python 中,可以直接用 Numpy 的 ndarray 来表示向量。

1
2
3
4
import numpy as np
a = np.array([-1, 2])
b = np.array([3, 1])
print a + b # [2 3]

\[ \mathbf{a} - \mathbf{b} = \begin{bmatrix} a_1 - b_1 \\ a_2 - b_2 \\ \ldots \\ a_n - b_n \end{bmatrix} \]

从几何角度讲,向量减相当于加上一个反向的向量。

1
2
3
4
import numpy as np
a = np.array([-1, 2])
b = np.array([3, 1])
print a - b # [-4, 1]

标量乘向量

标量 \(c\) 乘以向量 \(\mathbf{a}\) 定义为:

\[ c \cdot \mathbf{a} = \begin{bmatrix} c \cdot a_1 \\ c \cdot a_2 \\ \ldots \\ c \cdot a_n \end{bmatrix} = \begin{bmatrix} a_1 \cdot c \\ a_2 \cdot c \\ \ldots \\ a_n \cdot c \end{bmatrix} \]

绘图示意向量 \(\mathbf{a} = \begin{bmatrix} -1 \\ 2 \end{bmatrix}\) 乘以一个标量 3 得到 \(\begin{bmatrix} -3 \\ 6 \end{bmatrix}\) :

Python 实现:

1
2
3
import numpy as np
a = np.array([-1, 2])
print a * 3 #[-3, 6]

向量点积

向量的点积(又叫点乘)定义如下:

\[\vec{\mathbf{a}}\cdot \vec{\mathbf{b}} = \begin{bmatrix} a_1 \\ a_2 \\ \ldots \\ a_n\end{bmatrix} \cdot \begin{bmatrix} b_1 \\ b_2 \\ \ldots \\ b_n \end{bmatrix} = a_{1}b_{1} + a_{2}b_{2} + \ldots + a_{n}b_{n}\]

可见点积得到的是一个标量。

例如:

\[\begin{bmatrix} 3 \\ 5 \\ 2 \end{bmatrix} \cdot \begin{bmatrix} 1 \\ 4 \\ 7 \end{bmatrix} = 3 \cdot 1 + 5 \cdot 4 + 2 \cdot 7 = 37\]

Python 示例:

1
2
3
4
5
import numpy as np
a = np.array([3, 5, 2])
b = np.array([1, 4, 7])
print a.dot(b) # 37
print np.dot(a, b) # 37(另一种等价写法)

容易证明点积满足乘法交换律、分配律和结合律。

我们前面知道向量的长度定义为 \(\left\| \vec{\mathbf{v}} \right\| = \sqrt{v_{1}^{2} + v_{2}^{2} + \ldots + v_{n}^{2}}\),联立点积的定义,可以得出:

eq: 1 »
\[\left\| \vec{\mathbf{v}} \right\| = \sqrt{v_{1}^{2} + v_{2}^{2} + \ldots + v_{n}^{2}} = \sqrt{\vec{\mathbf{v}} \cdot \vec{\mathbf{v}}}\]

关于点积还有一个非常重要的性质,称为 柯西不等式 [4]

  • 对两个非 0 向量 \(\vec{\mathbf{x}}, \vec{\mathbf{y}} \in \mathbb{R}^{n}\),\(|\vec{\mathbf{x}} \cdot \vec{\mathbf{y}}| \le \left\|\vec{\mathbf{x}}\right\|\left\|\vec{\mathbf{y}}\right\|\)。
  • 当且仅当 \(\vec{\mathbf{x}} = c\vec{\mathbf{y}}\) 时,等式成立。

虽然受限于篇幅不去证明它,但这个性质非常重要,后面会有很多向量的理论都建立在它的基础之上。例如,对一个向量 \((\vec{\mathbf{x}} + \vec{\mathbf{y}})\) ,利用这个性质,结合公式 1,我们可以得到

\[ \begin{align} \left\|\vec{\mathbf{x}} + \vec{\mathbf{y}}\right\|^2 & = (\vec{\mathbf{x}} + \vec{\mathbf{y}})\cdot (\vec{\mathbf{x}} + \vec{\mathbf{y}}) \\\ & = \left\|\vec{\mathbf{x}}\right\|^2 + 2\vec{\mathbf{x}}\vec{\mathbf{y}} + \left\|\vec{\mathbf{y}}\right\|^2 \\\ & \le \left\|\vec{\mathbf{x}}\right\|^2 + 2\left\|\vec{\mathbf{x}}\right\|\left\|\vec{\mathbf{y}}\right\| + \left\|\vec{\mathbf{y}}\right\|^2 \end{align} \]

所以:

\[ \left\|\vec{\mathbf{x}} + \vec{\mathbf{y}}\right\|^2 \le (\left\|\vec{\mathbf{x}}\right\| + \left\|\vec{\mathbf{y}}\right\|)^2 \]

两边开平方得到:

\[ \left\|\vec{\mathbf{x}} + \vec{\mathbf{y}}\right\| \le \left\|\vec{\mathbf{x}}\right\| + \left\|\vec{\mathbf{y}}\right\| \]

这就得到了三角不等式。

从几何的角度来说,向量的点积与向量间夹角 \(\theta\) 的余弦有关:\[\vec{\mathbf{a}}\cdot\vec{\mathbf{b}} = \left\|\vec{\mathbf{a}}\right\|\left\|\vec{\mathbf{b}}\right\|cos\theta\],这意味着向量的点积其实反映了向量 \(\vec{\mathbf{a}}\) 在向量 \(\vec{\mathbf{b}}\) 上的 投影 ,即两个向量在同个方向上的相同程度。当两向量正交时,\(cos\theta\) 的值为0,点积的值为0,投影最小。当两向量平行时,\(cos\theta\) 的值为1,点积值最大,投影也最大。

观察上图,\(L\) 是 \(\vec{\mathbf{v}}\) 向量两端延伸出来的直线,即 \(L={c\vec{\mathbf{v}}|c\in \mathbb{R}}\)。记向量 \(\vec{\mathbf{x}}\) 在 \(L\) 上的投影为 \(Proj_L(\vec{\mathbf{x}})\)。根据点积的性质,可得:

\[ \begin{align} (\vec{\mathbf{x}}-\underbrace { c\vec{\mathbf{v}}}_{ Proj_L({\vec{\mathbf{x}}}) } )\cdot \vec{\mathbf{v}} &= 0 \\\ \vec{\mathbf{x}}\cdot \vec{\mathbf{v}} -c\vec{\mathbf{v}}\cdot \vec{\mathbf{v}} &= 0\\\ c\cdot \vec{\mathbf{v}} \cdot \vec{\mathbf{v}} &= \vec{\mathbf{x}}\cdot \vec{\mathbf{v}}\\\ c &= \frac{\vec{\mathbf{x}}\cdot \vec{\mathbf{v}}}{\vec{\mathbf{v}}\cdot \vec{\mathbf{v}}} \end{align} \]

有了 \(c\), 我们就可以求出投影 \(Proj_L({\vec{\mathbf{x}}})\) 为:

\[Proj_L({\vec{\mathbf{x}}}) = c\vec{\mathbf{v}} = (\frac{\vec{\mathbf{x}}\cdot \vec{\mathbf{v}}}{\vec{\mathbf{v}}\cdot \vec{\mathbf{v}}})\vec{\mathbf{v}}\]

例如,向量 \(\vec{\mathbf{a}} = \begin{bmatrix}1 \\ 2\end{bmatrix}\),向量 \(\vec{\mathbf{b}} = \begin{bmatrix}1 \\ 1\end{bmatrix}\),那么 \(\vec{\mathbf{a}}\) 在 \(\vec{\mathbf{b}}\) 方向 \(L\) 上的投影为:

\[Proj_L({\vec{\mathbf{a}}}) = c\vec{\mathbf{b}} = (\frac{\vec{\mathbf{a}}\cdot \vec{\mathbf{b}}}{\vec{\mathbf{b}}\cdot \vec{\mathbf{b}}})\vec{\mathbf{b}} = \frac{3}{2}\vec{\mathbf{b}}\]

Python 示例:

1
2
3
4
5
6
def get_projection(a, b):
return a.dot(b)*1.0*b/b.dot(b)
a = np.array([1, 2])
b = np.array([2, 2])
print get_projection(a, b) # [1.5 1.5]

向量外积

向量的(又叫叉乘、向量积、叉积)只在 \(\mathbb{R}^{2}\) 和 \(\mathbb{R}^{3}\) 中定义:

\(\mathbb{R}^{2}\) 的向量外积:

\[\begin{bmatrix} a_1 \\ a_2\end{bmatrix} \times \begin{bmatrix} b_1 \\ b_2 \end{bmatrix} = \begin{bmatrix} a_1 \cdot b_2 - a_2 \cdot b_1\end{bmatrix}\]

例如:

\[ \begin{bmatrix} 1 \\ 2 \end{bmatrix} \times \begin{bmatrix} 3 \\ 4 \end{bmatrix} = \begin{bmatrix} 1 \cdot 4 - 3 \cdot 2 \end{bmatrix} = \begin{bmatrix}-2\end{bmatrix} \]

\(\mathbb{R}^{3}\) 的向量外积:

\[\begin{bmatrix} a_1 \\ a_2 \\ a_3\end{bmatrix} \times \begin{bmatrix} b_1 \\ b_2 \\ b_3 \end{bmatrix} = \begin{bmatrix} a_2 \cdot b_3 - a_3 \cdot b_2 \\ a_3 \cdot b_1 - a_1 \cdot b_3 \\ a_1 \cdot b_2 - a_2 \cdot b_1\end{bmatrix}\]

例如:

\[ \begin{bmatrix} 3 \\ 5 \\ 2 \end{bmatrix} \times \begin{bmatrix} 1 \\ 4 \\ 7 \end{bmatrix} = \begin{bmatrix} 5 \cdot 7 - 2 \cdot 4 \\ 2 \cdot 1 - 3 \cdot 7 \\ 3 \cdot 4 - 5 \cdot 1\end{bmatrix} = \begin{bmatrix} 27 \\ -19 \\ 7\end{bmatrix} \]

可见向量间外积的结果会得到一个新的向量。

Python 示例:

1
2
3
4
import numpy as np
a = np.array([3, 5, 2])
b = np.array([1, 4, 7])
print np.cross(a, b) # [27, -19, 7]

外积的一个重要作用是可以得到一个和 \(\vec{\mathbf{a}}\) 、\(\vec{\mathbf{b}}\) 两个原向量正交的新向量 \(\vec{\mathbf{c}}\) ,且可以通过右手法则来确定新向量的方向(一个简单的确定满足“右手定则”的结果向量的方向的方法是这样的:若坐标系是满足右手定则的,当右手的四指从 \(\vec{\mathbf{a}}\) 以不超过180度的转角转向 \(\vec{\mathbf{b}}\) 时,竖起的大拇指指向是 \(\vec{\mathbf{c}}\) 的方向)。

从几何的角度来说,向量的外积与向量间夹角 \(\theta\) 的正弦有关:\[\left\|\vec{\mathbf{a}}\times\vec{\mathbf{b}}\right\| = \left\|\vec{\mathbf{a}}\right\|\left\|\vec{\mathbf{b}}\right\|sin\theta\],这意味着向量的外积反映了向量 \(\vec{\mathbf{a}}\) 与向量 \(\vec{\mathbf{b}}\) 的正交程度。当两向量平行时,\(sin\theta\) 的值为0,外积的值为0,正交程度最小。当两向量正交时,\(sin\theta\) 的值为1,外积值最大,正交程度最大。

矩阵向量积

当矩阵 \(\mathbf{A}\) 的列数与向量 \(\vec{\mathbf{x}}\) 的分量数相同时,矩阵和向量的积有定义:

\[\underset{m\times n}{A}\vec{\mathbf{x}}=\begin{bmatrix}a_{11} & a_{12} & \ldots & a_{1n} \\ a_{21} & a_{22} & \ldots & a_{2n} \\ \ldots \\ a_{m1} & a_{m2} & \ldots & a_{mn}\end{bmatrix}\begin{bmatrix}x_1 \\ x_2 \\ \ldots \\ x_n \end{bmatrix} = \begin{bmatrix}a_{11}x_1 + a_{12}x_2 + \ldots + a_{1n}x_n \\ a_{21}x_1 + a_{22}x_2 + \ldots + a_{2n}x_n \\ \ldots \\ a_{m1}x_1 + a_{m2}x_2 + \ldots + a_{mn}x_n \\ \end{bmatrix} \]

例如矩阵 \(\mathbf{A} = \begin{bmatrix}4 & 3 & 1 \\ 1 & 2 & 5\end{bmatrix}\) 乘以向量 \(\vec{\mathbf{x}} = \begin{bmatrix}5 \\ 2 \\ 7\end{bmatrix}\) 的结果为:

\[\begin{bmatrix}4\cdot 5 + 3\cdot 2 + 1\cdot 7 \\ 1 \cdot 5 + 2 \cdot 2 + 5 \cdot 7\end{bmatrix} = \begin{bmatrix}33 \\ 44\end{bmatrix}\]

Python 示例:

1
2
3
a = np.matrix('4 3 1;1 2 5')
x = np.array([[5], [2], [7]])
print a*x # [[33] [44]]

矩阵的向量积可以当成是矩阵的所有列向量的线性组合:

\[\underset { m\times n }{ \mathbf{A} } \vec { \mathbf{x} } =\begin{bmatrix} \underbrace { \begin{bmatrix} a_{ 11 } \\ a_{ 21 } \\ \ldots \\ a_{ m1 } \end{bmatrix} }_{ \vec { \mathbf{ V }_{ 1 } } } & \underbrace { \begin{bmatrix} a_{ 12 } \\ a_{ 22 } \\\ldots \\ a_{ m2 } \end{bmatrix} }_{ \vec { \mathbf{ V_{ 2 } } } } & \ldots & \underbrace { \begin{bmatrix} a_{ 1n } \\ a_{ 2n } \\ \ldots \\ a_{ mn } \end{bmatrix} }_{ \vec { \mathbf{ V_{ n } } } } \end{bmatrix}\begin{bmatrix} x_{ 1 } \\ x_{ 2 } \\ \ldots \\ x_{ n } \end{bmatrix}=x_1\vec{\mathbf{V}_1}+x_2\vec{\mathbf{V}_2}+\ldots+x_n\vec{\mathbf{V}_n}\]

而向量 \(\vec{\mathbf{x}}\) 的每一个分量可以看成是 \(\mathbf{A}\) 的每个列向量的加权。

一个矩阵其实就是一个线性变换。一个矩阵乘以一个向量后得到的向量,其实就相当于将这个向量进行了线性变换。

向量的转置

向量 \(\vec{\mathbf{V}} = \underbrace{\begin{bmatrix}v_1 \\ v_2 \\ \ldots \\ v_n \end{bmatrix}}_{n\times 1}\) 的转置定义为 \(\vec{\mathbf{V}}^T = \underbrace{\begin{bmatrix}v_1 & v_2 & \ldots & v_n \end{bmatrix}}_{1 \times n}\)

例如向量 \(\vec{\mathbf{A}} = \begin{bmatrix} 2 & 4 \end{bmatrix}\) 的转置就是 \(\vec{\mathbf{A}}^T = \begin{bmatrix} 2 \\ 4\end{bmatrix}\)。

Python 示例:

1
2
3
4
>>> a = np.array([[2, 4]])
>>> a.T
array([[2],
[4]])

注意上面声明 a 时用了两对 [] ,以生成一个二维向量。一维的向量转置结果是不会变化的:

1
2
3
>>> b = np.array([2, 4])
>>> b.T
array([2, 4])

向量的转置有一个性质:一个向量 \(\vec{\mathbf{v}}\) 点乘另一个向量 \(\vec{\mathbf{w}}\) ,其结果和向量 \(\vec{\mathbf{v}}\) 转置后和向量 \(\vec{\mathbf{w}}\) 做矩阵乘法相同。即 \(\vec{\mathbf{v}} \cdot \vec{\mathbf{w}} = \vec{\mathbf{v}}^T \vec{\mathbf{w}}\) 。

线性无关

张成空间

一组向量的张成空间说白了就是指这些向量随便线性组合后能够表示多少个向量。记为 \(span(\vec{\mathbf{a}}, \vec{\mathbf{b}})\)。

例如,对于 \(\mathbb{R}^{2}\) 空间中两个不平行的非0向量 \(\vec{\mathbf{a}} = \begin{bmatrix}2 \\ 1\end{bmatrix}\) 和向量 \(\vec{\mathbf{b}} = \begin{bmatrix} 0 \\ 3 \end{bmatrix}\) ,不难发现这两个向量能够表示二维空间中任一其他向量,即 \(span(\vec{\mathbf{a}}, \vec{\mathbf{b}}) = \mathbb{R}^{2}\)。证明如下:

对于 \(\mathbb{R}^{2}\) 中任一向量 \(\begin{bmatrix}x \\y \end{bmatrix}\) ,假设可以由 \(\vec{\mathbf{a}}\) 和 \(\vec{\mathbf{b}}\) 线性组合而成,那么有:

\[ c_1 \begin{bmatrix}2 \\ 1\end{bmatrix} + c_2 \begin{bmatrix} 0 \\ 3 \end{bmatrix} = \begin{bmatrix} x \\ y \end{bmatrix} \]

即:

\[ \left\{ \begin{align} c_1 \cdot 2 & + c_2 \cdot 0 &= x\\\ c_1 \cdot 1 & + c_2 \cdot 3 &= y \end{align} \right. \]

求解该方程得:

\[ \left\{ \begin{align} c_1 &= \frac{x}{2}\\ c_2 &= \frac{y}{3} - \frac{x}{6} \end{align} \right. \]

由于 \(x\)、\(y\) 的值已确定,所以 \(c_1\)、\(c_2\) 的值也必然唯一。

线性相关和线性无关

当一个向量集合里的每个向量都对张成的空间有贡献时,称这个向量集合 线性无关 。反之称为 线性相关 。能够表示一个空间的最少向量组合称为空间的

听起来有点难理解,其实就是非常简单的道理:假如一个向量集合中存在某个向量能由集合里的其他向量线性组合而成,那这个集合对于张成空间而言就存在多余的向量。此时就是线性相关;反之,假如集合里每一个元素都没法由其他元素组合而成,那么这个集合每个元素都对张成空间有贡献,这个集合就是线性无关的。

例如,对于上述的例子,如果再增加一个向量 \(\vec{\mathbf{c}} = \begin{bmatrix} 5 \\ 2\end{bmatrix}\) ,由于 \(\vec{\mathbf{c}}\) 可以由 \(\vec{\mathbf{a}}\) 和 \(\vec{\mathbf{b}}\) 线性组合而成,由 \(\mathbf{a}\) 、\({\mathbf{b}}\) 和 \({\mathbf{c}}\) 共同张成的空间并没有变化,仍然是 \(\mathbb{R}^{2}\),因此称集合 \(\left\{\vec{\mathbf{a}}, \vec{\mathbf{b}}, \vec{\mathbf{c}}\right \}\) 线性相关。

如果一个向量集合线性无关,且集合里的每个向量长度都为 1 ,那么就称这个集合为 标准正交集合 (Othonormal Set),称这个集合的基为 标准正交基

基可以理解为坐标系的轴。我们平常用到的大多是直角坐标系,在线形代数中可以把这个坐标系扭曲、拉伸、旋转,称为基的变换。我们可以按我们的需求去设定基,但是基的轴之间必须是线形无关的。

判断是否线性相关

一个向量集合 \(s = {v_1, v_2, \ldots, v_n}\) 线性相关的充分必要条件是存在一部分非0系数使得 \(c_1 v_1 + c_2 v_2 + \ldots + c_n v_n = \mathbf{0} = \begin{bmatrix} 0 \\ 0 \\ \ldots \\ 0\end{bmatrix}\) 。

例如有向量 \(\begin{bmatrix}2 \\ 1\end{bmatrix}\) 和 \(\begin{bmatrix}3 \\ 2\end{bmatrix}\),则可以先写出如下的等式:

\[c_1 \begin{bmatrix}2 \\ 1\end{bmatrix} + c_2 \begin{bmatrix}3 \\ 2\end{bmatrix} = \begin{bmatrix}0 \\ 0\end{bmatrix}\]

容易求解得 \(\begin{bmatrix}c_1 \\ c_2\end{bmatrix} = \begin{bmatrix}0 \\ 0\end{bmatrix}\),说明两个向量线性无关。也说明这两个向量可以张成 \(\mathbb{R}^{2}\)。

类似地,对于三个 \(\mathbb{R}^{3}\) 中的向量 \(\begin{bmatrix}2 \\ 0 \\ 0\end{bmatrix}\)、\(\begin{bmatrix}0 \\ 1 \\ 0\end{bmatrix}\) 和 \(\begin{bmatrix}0 \\ 0 \\ 7\end{bmatrix}\),不难判断这三个向量是线性无关的,他们共同张成了 \(\mathbb{R}^3\) 空间。

而对于向量集合 \(\left\{\begin{bmatrix}2 \\ 1\end{bmatrix}, \begin{bmatrix}3 \\ 2\end{bmatrix}, \begin{bmatrix}1 \\ 2 \end{bmatrix}\right\}\) ,不难算出存在非 0 的系数 \(\begin{bmatrix}c_1 \\ c_2 \\ c_3\end{bmatrix} = \begin{bmatrix}-4 \\ 3 \\ -1\end{bmatrix}\) 使得 \(c1 \begin{bmatrix}2 \\ 1\end{bmatrix} + c_2 \begin{bmatrix}3 \\ 2\end{bmatrix} + c_3 \begin{bmatrix}1 \\ 2 \end{bmatrix} = \begin{bmatrix}0 \\ 0\end{bmatrix}\)。因此集合 \(\left\{\begin{bmatrix}2 \\ 1\end{bmatrix}, \begin{bmatrix}3 \\ 2\end{bmatrix}, \begin{bmatrix}1 \\ 2 \end{bmatrix}\right\}\) 线性相关。

张量

张量(tensor)这个术语常常在机器学习的库中出现。Google 的 TensorFlow 甚至直接以它命名了。

其实,学完了矩阵和向量,张量并不是什么新鲜的概念。使用这个词汇的目的是为了表述统一,张量可以看作是向量、矩阵的自然推广,我们用张量来表示广泛的数据类型。

规模最小的张量是0阶张量,即标量,也就是一个数。

当我们把一些数有序的排列起来,就形成了1阶张量,也就是一个向量。

如果我们继续把一组向量有序的排列起来,就形成了2阶张量,也就是一个矩阵。

把矩阵摞起来,就是3阶张量,我们可以称为一个立方体,具有3个颜色通道的彩色图片就是一个这样的立方体。

把矩阵摞起来,好吧这次我们真的没有给它起别名了,就叫4阶张量了,不要去试图想像4阶张量是什么样子,它就是个数学上的概念。

张量的阶数有时候也称为维度(dimension),或者轴(axis)。譬如一个矩阵 \(\begin{bmatrix}1 & 3 \\ 2 & 4\end{bmatrix}\),是一个 2 阶张量,有两个维度或轴,沿着第 0 个轴(为了与python的计数方式一致,本文档维度和轴从0算起)你看到的是 \(\begin{bmatrix}1 \\ 2\end{bmatrix}\)、\(\begin{bmatrix}3 \\ 4\end{bmatrix}\) 两个向量,沿着第 1 个轴你看到的是 \(\begin{bmatrix}1 \\ 3\end{bmatrix}\)、\(\begin{bmatrix}2 \\ 4\end{bmatrix}\) 两个向量。

要理解“沿着某个轴”是什么意思,不妨试着运行一下下面的代码:

1
2
3
4
5
6
7
8
import numpy as np
a = np.array([[1,2],[3,4]])
sum0 = np.sum(a, axis=0)
sum1 = np.sum(a, axis=1)
print sum0 # [4 6]
print sum1 # [3 7]

线性代数进阶

阶梯形矩阵

阶梯形矩阵是一类非常实用的工具,可以帮助我们求解出线性空间的基,这就能用在诸如计算解不唯一的方程组之类的问题上。

阶梯形矩阵

若矩阵 \(\mathbf{A}\) 满足两条件:

  1. 若有零行(元素全为0的行),则零行应在最下方;
  2. 非零首元(即非零行的第一个不为零的元素)的列标号随行标号的增加而严格递增。

则称此矩阵 \(\mathbf{A}\) 为阶梯形矩阵。

示例:

\[ \begin{bmatrix} 2 & 0 & 2 & 1 \\ 0 & 5 & 2 & -2 \\ 0 & 0 & 3 & 2 \\ 0 & 0 & 0 & 0 \end{bmatrix} \]

行简化阶梯形矩阵

若矩阵 \(\mathbf{A}\) 满足两条件:

  1. 它是阶梯形矩阵;
  2. 非零首元所在的列除了非零首元外,其余元素全为0。

则称此矩阵 \(\mathbf{A}\) 为行简化阶梯形矩阵。

示例:

\[ \begin{bmatrix} 2 & 0 & 2 & 1 \\ 0 & 5 & 2 & -2 \\ 0 & 0 & 3 & 2 \\ 0 & 0 & 0 & 0 \end{bmatrix} \]

行最简形矩阵

若矩阵 \(\mathbf{A}\) 满足两条件:

  1. 它是行简化阶梯形矩阵;
  2. 非零首元都为1

则称此矩阵 \(\mathbf{A}\) 为行最简形矩阵。

将矩阵化简成行最简阶梯形

对如下矩阵

\[ \begin{bmatrix} 1 & 2 & 1 & 1 & 7\\ 1 & 2 & 2 & -1 & 12\\ 2 & 4 & 0 & 6 & 4 \end{bmatrix} \]

,使用初等变换可以将这个矩阵转换成如下的形式:

\[ \begin{bmatrix} 1 & 2 & 1 & 1 & 7\\ 1 & 2 & 2 & -1 & 12\\ 2 & 4 & 0 & 6 & 4 \end{bmatrix} \rightarrow \begin{bmatrix} 1 & 2 & 1 & 1 & 7\\ 0 & 0 & 1 & -2 & 5\\ 2 & 4 & 0 & 6 & 4 \end{bmatrix} \rightarrow \begin{bmatrix} 1 & 2 & 1 & 1 & 7\\ 0 & 0 & 1 & -2 & 5\\ 0 & 0 & -2 & 4 & -10 \end{bmatrix} \rightarrow \begin{bmatrix} 1 & 2 & 1 & 1 & 7\\ 0 & 0 & 1 & -2 & 5\\ 0 & 0 & 0 & 0 & 0 \end{bmatrix} \rightarrow \begin{bmatrix} 1 & 2 & 0 & 3 & 2\\ 0 & 0 & 1 & -2 & 5\\ 0 & 0 & 0 & 0 & 0 \end{bmatrix} \]

行最简形非常实用。例如,对于下面的方程组:

\[\left\{ \begin{eqnarray} x_1 + 2x_2 + x_3 + x_4 &=& 7 \\\ x_1 + 2x_2 + 2x_3 - x_4 &=& 12 \\\ 2x_1 + 4x_2 + 6x_4 &=& 4 \end{eqnarray} \right. \]

只有三个方程,肯定无法求解出四个未知数(此时如果在用 numpy.linalg.solve 求解这个矩阵会引发 LinAlgError ),但是通过化成行最简形,我们可以进一步找出变量的限制关系。先将方程组表达成增广矩阵形式:

\[ \begin{bmatrix} 1 & 2 & 1 & 1 & 7\\ 1 & 2 & 2 & -1 & 12\\ 2 & 4 & 0 & 6 & 4 \end{bmatrix} \]

这个矩阵和完全和我们上一步给出的矩阵相同,因此其行简化阶梯性就是

\[ \begin{bmatrix} 1 & 2 & 0 & 3 & 2\\ 0 & 0 & 1 & -2 & 5\\ 0 & 0 & 0 & 0 & 0 \end{bmatrix} \]

对于方程组,非0首元位置对应的变量就叫做主元变量,其他的变量就叫做自由变量。例如上面的行最简形,\(x_1\) 和 \(x_3\) 是首元变量,\(x_2\) 和 \(x_4\) 就是自由变量。我们可以将方程改写成下面的形式:

\[ \left\{ \begin{eqnarray} x_1 &=& 2 - 2x_2 - 3x_4 \\\ x_3 &=& 5 + 2x_4 \end{eqnarray} \right. \]

然后可以得到:

\[ \begin{bmatrix} x_{ 1 } \\ x_{ 2 } \\ x_{ 3 } \\ x_{ 4 } \end{bmatrix}=\begin{bmatrix} 2 \\ 0 \\ 5 \\ 0 \end{bmatrix}+x_{ 2 }\underbrace { \begin{bmatrix} -2 \\ 1 \\ 0 \\ 0 \end{bmatrix} }_{ \vec{\mathbf{a}} } +x_{ 4 }\underbrace{\begin{bmatrix} -3 \\ 0 \\ 2 \\ 1 \end{bmatrix}}_{\vec{\mathbf{b}}} \]

观察这个结果,方程组的解集就是向量 \(\vec{\mathbf{a}}\) 和向量 \(\vec{\mathbf{b}}\) 的线性组合。这两个向量张成了 \(\mathbb{R}^4\) 中的一个平面。

线性子空间

在前面的内容中我们已经多少涉及到了一些关于空间、张成空间的知识了。有时候我们需要从一个空间 \(K\) 里头挑出一些向量张成一个新的空间 \(\mathbf{W}\) ,这个空间 \(\mathbf{W}\) 就是原来的向量 \(\mathbf{K}\) 的子空间。

定理:设 \(\mathbf{V}\) 是在域 \(\mathbf{K}\) 上的向量空间,并设 \(\mathbf{W}\) 是 \(\mathbf{V}\) 的子集。则 \(\mathbf{W}\) 是个子空间,当且仅当它满足下列三个条件:

  1. 零向量 0 在 \(\mathbf{W}\) 中。
  2. 加法封闭:如果 \(\vec{\mathbf{u}}\) 和 \(\vec{\mathbf{v}}\) 是 \(\mathbf{W}\) 的元素,则向量和 \(\mathbf{\vec{\mathbf{u}}+\vec{\mathbf{v}}}\) 是 \(\mathbf{W}\) 的元素。
  3. 标量乘法封闭:如果 \(\vec{\mathbf{u}}\) 是 \(\mathbf{W}\) 的元素而 \(c\) 是标量,则标量积 \(c\vec{\mathbf{u}}\) 是 \(\mathbf{W}\) 的元素。

子空间的引入有助于我们更专注于某类线性组合,从中找出这些子空间的特点,以及与原来的空间的关系。下面将列举几种典型的子空间。

零空间

矩阵 \(\mathbf{A}\) 的零空间 \(N(\mathbf{A})\) 就是由满足 \(\mathbf{A}\vec{\mathbf{x}}=0\) 的所有向量 \(\vec{\mathbf{x}}\) 的集合。

要求解一个矩阵的零空间,可以先将其化简成行最简形。例如矩阵 $\mathbf{A} = \begin{bmatrix} 1 & 1 & 1 & 1 \\ 1 & 2 & 3 & 4 \\ 4 & 3 & 2 & 1 \end{bmatrix} $,为了计算零空间,可以写出如下的等式:

\[\begin{bmatrix} 1 & 1 & 1 & 1 \\ 1 & 2 & 3 & 4 \\ 4 & 3 & 2 & 1 \end{bmatrix} \begin{bmatrix} x_1 \\ x_2 \\ x_3 \\ x_4 \end{bmatrix} = \begin{bmatrix} 0 \\ 0 \\ 0 \end{bmatrix}\]

展开得到如下的方程组:

\[ \left\{ \begin{eqnarray} x_1 + x_2 + x_3 + x_4 &=& 0 \\\ x_1 + 2x_2 + 3x_3 + 4x_4 &=& 0 \\\ 4x_1 + 3x_2 + 2x_4 + x_4 &=& 0 \end{eqnarray} \right. \]

参考 化简成行最简阶梯形 一节里介绍的方法,先把上面的方程组表示成增广矩阵:

\[ \begin{bmatrix} 1 & 1 & 1 & 1 & 0 \\ 1 & 2 & 3 & 4 & 0 \\ 4 & 3 & 2 & 1 & 0 \end{bmatrix} \]

然后将其转换成行最简形:

\[ \begin{bmatrix} 1 & 0 & -1 & -2 & 0 \\ 0 & 1 & 2 & 3 & 0 \\ 0 & 0 & 0 & 0 & 0 \end{bmatrix} \]

最终求解得到:

\[ \begin{bmatrix} x_{ 1 } \\ x_{ 2 } \\ x_{ 3 } \\ x_{ 4 } \end{bmatrix}=x_{ 3 }\underbrace { \begin{bmatrix} 1 \\ -2 \\ 1 \\ 0 \end{bmatrix} }_{ \vec{\mathbf{a}} } +x_{ 4 }\underbrace{\begin{bmatrix} 2 \\ -3 \\ 0 \\ 1 \end{bmatrix}}_{\vec{\mathbf{b}}} \]

因此矩阵 \(\mathbf{A}\) 的零空间就是由上式中的 \(\vec{\mathbf{a}}\) 向量和 \(\vec{\mathbf{b}}\) 向量张成的空间。即

\[N(\mathbf{A}) = span\left(\begin{bmatrix} 1 \\ -2 \\ 1 \\ 0 \end{bmatrix} \begin{bmatrix} 2 \\ -3 \\ 0 \\ 1 \end{bmatrix}\right)\]

另外,上面得到的这个行最简形有两个自由变量,就称矩阵 \(\mathbf{A}\) 的 零度 为 2。零度等于 \(\mathbf{A}\vec{\mathbf{x}} = 0\) 化成行最简形后自由变量的个数。

零空间其实和线性无关其实有很大的联系。一个矩阵的零空间为 \(\vec{\mathbf{0}}\) 的充分必要条件是这个矩阵的所有列线性无关。

列空间

矩阵的列空间就是由每一列的向量张成的空间。对于矩阵 \(\underset { m\times n }{ \mathbf{A} } =\begin{bmatrix} \underbrace { \begin{bmatrix} a_{ 11 } \\ a_{ 21 } \\ \ldots \\ a_{ m1 } \end{bmatrix} }_{ \vec { \mathbf{ V }_{ 1 } } } & \underbrace { \begin{bmatrix} a_{ 12 } \\ a_{ 22 } \\\ldots \\ a_{ m2 } \end{bmatrix} }_{ \vec { \mathbf{ V_{ 2 } } } } & \ldots & \underbrace { \begin{bmatrix} a_{ 1n } \\ a_{ 2n } \\ \ldots \\ a_{ mn } \end{bmatrix} }_{ \vec { \mathbf{ V_{ n } } } } \end{bmatrix}\),那么矩阵 \(\mathbf{A}\) 的列空间就是

\[C(\mathbf{A}) = span(\vec{v_1}, \vec{v_2}, \ldots, \vec{v_n})\]

例如,矩阵 \(\mathbf{A} = \begin{bmatrix}1 & 1 & 1 & 1 \\ 1 & 2 & 3 & 4 \\4 & 3 & 2 & 1\end{bmatrix}\) 的列空间是 \(C(\mathbf{A}) = span\left(\begin{bmatrix}1 \\ 1 \\ 4\end{bmatrix}\begin{bmatrix}1 \\ 2 \\ 3\end{bmatrix}\begin{bmatrix}1 \\ 3 \\ 2\end{bmatrix}\begin{bmatrix}1 \\ 4 \\ 1\end{bmatrix}\right)\)

把一个矩阵化成行最简形后,这个矩阵的不相关主列(基底)的个数就称为矩阵的(Rank),或者叫维数。

例如,上面的矩阵 \(\mathbf{A}\) 化成最简形矩阵是(参考上节的化简结果):

\[ \begin{bmatrix} 1 & 0 & -1 & -2 \\ 0 & 1 & 2 & 3 \\ 0 & 0 & 0 & 0 \end{bmatrix} \]

从结果可以看出这个矩阵的主列有 2 个,而且是线性无关的。所以矩阵 \(\mathbf{A}\) 的秩为 2 ,即 \(rank(\mathbf{A}) = 2\)。

矩阵的秩有一个特性:矩阵 \(\mathbf{A}\) 的秩等于矩阵 \(\mathbf{A}\) 的转置的秩。即 \(Rank(\mathbf{A}) = Rank(\mathbf{A^T})\)

在 Python 中,可以使用 Numpy 包中的 linalg.matrix_rank 方法计算矩阵的秩:

1
2
a = np.matrix('1 1 1 1;1 2 3 4;4 3 2 1')
print np.linalg.matrix_rank(a) # 2

注意 在 Numpy 中的秩和线性代数里的秩是不同的概念。在NumPy中维度(dimensions)叫做轴(axes),轴的个数叫做秩。

import numpy as np
a = np.matrix('1 1 1 1;1 2 3 4; 0 0 1 0')
print a.ndim  # 2(维度)
print np.rank(a)  # 2(a.ndim 的别名,已经过时)
print np.linalg.matrix_rank(a)  # 3(秩)

行空间

有了列空间的定义,行空间顾名思义就是矩阵的每一行转置得到的向量张成的子空间,也就是矩阵的转置的列空间,记为 \(R(\mathbf{A}) = C(\mathbf{A}^T)\)。

例如,矩阵 \(\mathbf{A} = \begin{bmatrix}1 & 1 & 1 & 1 \\ 1 & 2 & 3 & 4 \\4 & 3 & 2 & 1\end{bmatrix}\) 的行空间是 \(R(\mathbf{A}) = C(\mathbf{A}^T) = span\left(\begin{bmatrix}1 \\ 1 \\ 1 \\ 1\end{bmatrix}\begin{bmatrix}1 \\ 2 \\ 3 \\ 4\end{bmatrix}\begin{bmatrix}4 \\ 3 \\ 2 \\ 1\end{bmatrix}\right)\)。

左零空间

矩阵 \(\mathbf{A}\) 的左零空间是 \(\mathbf{A}\) 的转置的零空间。即:

\[N(\mathbf{A}^T) = \left\{ \vec{\mathbf{x}} | \mathbf{A}^{T} \vec{\mathbf{x}} = \vec{\mathbf{0}} \right\} = \left\{ \vec{\mathbf{x}} | \vec{\mathbf{x}}^{T} \mathbf{A} = \vec{\mathbf{0}}^{T} \right\}\]

例如,矩阵 \(\mathbf{B} = \begin{bmatrix}1 & 1 & 4 \\ 1 & 2 & 3 \\1 & 4 & 2\\ 1 & 3 & 1\end{bmatrix}\) 的转置是矩阵 \(\mathbf{A} = \mathbf{A} = \begin{bmatrix}1 & 1 & 1 & 1 \\ 1 & 2 & 3 & 4 \\4 & 3 & 2 & 1\end{bmatrix}\) ,因此左零空间是 \(N(\mathbf{B^T}) = N(\mathbf{A}) = span\left(\begin{bmatrix} 1 \\ -2 \\ 1 \\ 0 \end{bmatrix} \begin{bmatrix} 2 \\ -3 \\ 0 \\ 1 \end{bmatrix}\right)\)

由于转置是对称的,所以矩阵 \(\mathbf{A}\) 的转置的左零空间也是矩阵 \(\mathbf{A}\) 的零空间。

子空间的正交补

假设 \(\mathbf{V}\) 是 \(\mathbb{R}^n\) 的一个子空间,那么 \(\mathbf{V}\) 的正交补 \(\mathbf{V}^{\bot}\) 也是一个子空间,定义为 \(\left\{\vec{\mathbf{x}} | \vec{\mathbf{x}} \vec{\mathbf{v}}=0\right\}\),也即是 \(\mathbb{R}^{n}\) 中所有正交于 \(\mathbf{V}\) 的向量所组成的子空间。

由于正交是对称的,所以正交补也是对称的。一个子空间的正交补的正交补依然等于这个子空间。

矩阵的零空间是行空间的正交补[5],即 \(N(\mathbf{A}) = R(\mathbf{A})^{\bot}\)。反过来,矩阵的左零空间是列空间的正交补,即 \(N(\mathbf{B}^T) = C(\mathbf{B})^{\bot}\)。

最小二乘逼近

最小二乘法是一个实用的数学工具,利用它可以在方程无解的情况下给出近似解。在机器学习中,最小二乘逼近也是一个重要的拟合方法。

假设有一个方程

\[ \underset{n\times k}{\mathbf{A}}\vec{\mathbf{x}} = \vec{\mathbf{b}} \]

无解。把上式写成:

\[ \vec{a_1}\vec{\mathbf{x}} + \vec{a_2}\vec{\mathbf{x}} + \ldots + \vec{a_k}\vec{\mathbf{x}} = \vec{\mathbf{b}} \]

无解就意味着 \(\mathbf{A}\) 的所有列向量的张成空间不包括向量 \(\vec{\mathbf{b}}\) 。即 \(\vec{\mathbf{b}} \notin span(C(\mathbf{A}))\)。

我们可以通过最小二乘法求解出近似解。即是要让找出一些向量 \(\vec{\mathbf{x}^*}\) 使得 \(\left\|\vec{\mathbf{b}}-\mathbf{A}\vec{\mathbf{x}^*}\right\|\) 最小。用向量 \(\vec{\mathbf{V}}\) 代表 \(\mathbf{A}\vec{\mathbf{x}^*}\) ,有:

\[ \left\| \begin{bmatrix} \vec{b_1}-\vec{v_1}\\ \vec{b_2}-\vec{v_2}\\ \ldots\\ \vec{b_n}-\vec{v_n}\\ \end{bmatrix} \right\|^2 = (b_1-v_1)^2 + (b_2-v_2)^2 + \ldots + (b_n-v_n)^2 \]

把这个值最小化的过程就叫做最小二乘逼近

如何求出 \(\mathbf{A}\vec{\mathbf{x}^*}\) 这个近似值呢?从几何上考虑,列空间可以看成空间中张成的一个平面,而向量 \(\vec{\mathbf{b}}\) 并不落在这个平面上。但我们知道,在这个平面上与向量 \(\vec{\mathbf{b}}\) 最接近的向量就是它的投影!所以,

\[ \mathbf{A}\vec{\mathbf{x}^*} = Proj_{C(\mathbf{A})}\vec{\mathbf{b}} \]

直接计算 \(Proj_{C(\mathbf{A})}\vec{\mathbf{b}}\) 并不简单。不过,\(\vec{\mathbf{b}}-\mathbf{A}\vec{\mathbf{x}}\) 其实就是 \(\mathbf{A}\vec{\mathbf{x}}\) 的正交补,所以一个简单的求解方法是将原来无解的方程左乘一个 \(\mathbf{A}\) 的转置再求解:

\[ \mathbf{A}^T\mathbf{A}\vec{\mathbf{x}^*} = \mathbf{A}^T\vec{\mathbf{b}} \]

得出的解就是原方程的近似解。

实例1:求解方程

问题:求解如下方程组

\[ \left\{ \begin{eqnarray} x + y &=& 3 \\\ x - y &=& -2 \\\ y &=& 1 \end{eqnarray} \right. \]

将三个方程表示的直线画出来,可以看出这三条直线并没有交点:

如何找出一个与三条直线距离最近的一个点呢?这时候我们的最小二乘逼近就派上用场了。

先将方程写成矩阵和向量的形式:

\[ \underbrace{ \begin{bmatrix} 1 & 1 \\ 1 & -1 \\ 0 & 1 \end{bmatrix} }_{\mathbf{A}} \underbrace{ \begin{bmatrix} x \\ y \end{bmatrix} }_{\vec{\mathbf{x}}} = \underbrace{ \begin{bmatrix} 3 \\ -2 \\ 1 \end{bmatrix} }_{\vec{\mathbf{b}}} \]

这个等式的最小二乘逼近就是:

\[ \begin{align} \begin{bmatrix} 1 & 1 & 0 \\ 1 & -1 & 1\\ \end{bmatrix} \begin{bmatrix} 1 & 1 \\ 1 & -1 \\ 0 & 1 \end{bmatrix} \begin{bmatrix} x^* \\ y^* \end{bmatrix} & = \begin{bmatrix} 1 & 1 & 0 \\ 1 & -1 & 1\\ \end{bmatrix} \begin{bmatrix} 3 \\ -2 \\ 1 \end{bmatrix} \\\ \begin{bmatrix} 2 & 0 \\ 0 & 3 \end{bmatrix} \begin{bmatrix} x^* \\ y^* \end{bmatrix} & = \begin{bmatrix} 1 \\ 6 \end{bmatrix} \end{align} \]

由于是二阶方程,可以很容易求出矩阵 \(\begin{bmatrix}2 & 0 \\ 0 & 3\end{bmatrix}\) 的逆是 \(\begin{bmatrix}\frac{1}{2} & 0 \\ 0 & \frac{1}{3}\end{bmatrix}\),所以:

\[ \begin{bmatrix} x^* \\ y^* \end{bmatrix} = \begin{bmatrix}\frac{1}{2} & 0 \\ 0 & \frac{1}{3}\end{bmatrix} \begin{bmatrix} 1 \\ 6 \end{bmatrix} = \begin{bmatrix} \frac{1}{2} \\ 2 \end{bmatrix} \]

因此 \(\begin{bmatrix}\frac{5}{2} \\\frac{2}{3}\end{bmatrix}\) 就是方程组的近似解。

在 Python 中,可以使用 numpy.linalg.lstsq 方法来求解最小二乘逼近。

1
2
3
4
5
>>> a = np.array([[1, 1], [1, -1], [0, 1]])
>>> b = np.array([3, -2, 1])
>>> x = np.linalg.lstsq(a,b)
>>> print x
(array([ 0.5, 2. ]), array([ 1.5]), 2, array([ 1.73205081, 1.41421356]))

numpy.linalg.lstsq 的返回包括四个部分:

  1. 最小二乘逼近解。如果 b 是二维的,那么这个逼近的结果有多个列,每一列是一个逼近解。对于上例,逼近解就是 \(\begin{bmatrix}0.5 \\ 2 \end{bmatrix}\) 。
  2. 残差。即每一个 b - a*x 的长度的和。对于上例,残差是 1.5 。
  3. 矩阵 a 的秩。对于上例,矩阵 a 的秩为 2 。
  4. 矩阵 a 的奇异值。对于上例,矩阵 a 的奇异值为 \(\begin{bmatrix}1.73205081 \\ 1.41421356\end{bmatrix}\)

实例2:线性回归

问题:给定4个坐标点 \((-1, 0)\), \((0, 1)\), \((1, 2)\), \((2, 1)\) ,求一条经过这些点的直线 \(y=mx+b\)。

将四个点画图如下:

显然这样的直线并不存在。然而我们能够使用最小二乘逼近,找到一条尽可能接近这些点的直线。将四个点表示成方程组的形式:

\[ \left\{ \begin{eqnarray} f(-1) &= -m + b = 0\\\ f(0) &= 0 + b = 1\\\ f(1) &= m + b = 2\\\ f(2) &= 2m + b = 1 \end{eqnarray} \right. \]

还是那个套路,将方程组表示成矩阵和向量的形式:

\[ \underbrace{ \begin{bmatrix} -1 & 1 \\ 0 & 1 \\ 1 & 1 \\ 2 & 1 \end{bmatrix} }_{\mathbf{A}} \underbrace{ \begin{bmatrix} m\\ b \end{bmatrix} }_{\vec{\mathbf{x}}} = \underbrace{ \begin{bmatrix} 0\\ 1\\ 2\\ 1 \end{bmatrix} }_{\vec{\mathbf{b}}} \]

这个等式的最小二乘逼近就是:

\[ \begin{align} \begin{bmatrix} -1 & 0 & 1 & 2 \\ 1 & 1 & 1 & 1 \end{bmatrix} \begin{bmatrix} -1 & 1 \\ 0 & 1 \\ 1 & 1 \\ 2 & 1 \end{bmatrix} \begin{bmatrix} m^*\\ b^* \end{bmatrix} &= \begin{bmatrix} -1 & 0 & 1 & 2 \\ 1 & 1 & 1 & 1 \end{bmatrix} \begin{bmatrix} 0\\ 1\\ 2\\ 1 \end{bmatrix}\\\ \begin{bmatrix} 6 & 2 \\ 2 & 4 \end{bmatrix} \begin{bmatrix} m^*\\ b^* \end{bmatrix} &= \begin{bmatrix} 4\\ 4 \end{bmatrix} \end{align} \]

容易求得 \(\begin{bmatrix}6 & 2\\2 & 4\end{bmatrix}\) 的逆为 \(\frac{1}{20}\begin{bmatrix}4 & -2\\-2 & 6\end{bmatrix}\),因此

\[\begin{bmatrix}m^*\\b^*\end{bmatrix} = \frac{1}{20}\begin{bmatrix}4 & -2\\-2 & 6\end{bmatrix}\begin{bmatrix}4 \\ 4\end{bmatrix} = \frac{1}{20}\begin{bmatrix}8 \\ 16\end{bmatrix} = \begin{bmatrix}\frac{2}{5} \\ \frac{4}{5}\end{bmatrix}\]

将直线 \(y = \frac{2}{5}x + \frac{4}{5}\) 绘图如下所示:

这就是所求的直线的近似解。

Python 示例如下:

1
2
3
4
5
>>> a = np.matrix('-1 1;0 1;1 1;2 1')
>>> b = np.array([0, 1, 2, 1])
>>> x = np.linalg.lstsq(a, b)
>>> print x
(array([ 0.4, 0.8]), array([ 1.2]), 2, array([ 2.68999405, 1.66250775]))

特征向量

“特征”在模式识别和图像处理中是非常常见的一个词汇。我们要认识和描绘一件事物,首先得找出这个事物的特征。同样的道理,要让计算机识别一件事物,首先就要让计算机学会理解或者抽象出事物的特征。什么样的东西能当成特征呢?那必须是能“放之四海皆准”的依据,不论个体如何变换,都能从中找到这类群体共有的特点。例如,计算机视觉中常用的 SIFT 特征点 是一种很经典的用于视觉跟踪的特征点,即使被跟踪的物体的尺度、角度发生了变化,这种特征点依然能够找到关联。而谷歌的计算机在观看了一堆视频后能够识别出猫脸[6],说明谷歌的计算机已经能够抽象出猫脸的特征。不管黑猫白猫,只要符合猫脸特征,都能被识别成猫。

在线性代数中,“特征” 就是一种更抽象的描述。我们知道,矩阵乘法对应了一个变换,是把任意一个向量变成另一个方向或长度都大多不同的新向量。在这个变换的过程中,原向量主要发生旋转、伸缩的变化。如果矩阵对某一个向量或某些向量只发生伸缩(尺度)变换,而没有产生旋转的效果(也就意味着张成的子空间没有发生改变),这样的向量就认为是特征向量。

\[\mathbf{T}(\vec{\mathbf{v}}) = \underbrace{\mathbf{A}}_{n\times n}\vec{\mathbf{v}} = \underbrace{\lambda}_{特征值} \overbrace{\vec{\mathbf{v}}}^{特征向量}\]

其中, \(T\) 是一种线性变换,我们知道线性变换可以用矩阵向量积来表示,因此可以表示成 \(\mathbf{A}\vec{\mathbf{v}}\) 。\(\mathbf{A}\) 是一个 \(n\times n\) 的方阵。\(\vec{\mathbf{v}}\) 就是特征向量(Eigen Vector),也就是能被伸缩的向量(要求是非 \(\mathbf{0}\) 向量),而 \(\lambda\) 是特征向量 \(\vec{\mathbf{v}}\) 所对应的特征值,也就是伸缩了多少。如果特征值是负数,那说明了矩阵不但把向量拉长(缩短)了,而且让向量指向了相反的方向。

简而言之,特征向量就是在线性变化当中不变的向量。

听起来很抽象,放个例子就清楚了。下图出自 wikipedia的《特征向量》一文:

在这个仿射变换中,蒙娜丽莎的图像被变形,但是中心的纵轴在变换下保持不变。(注意:角落在右边的图像中被裁掉了。)蓝色的向量,从胸部到肩膀,其方向改变了,但是红色的向量,从胸部到下巴,其方向不变。因此红色向量是该变换的一个特征向量,而蓝色的不是。因为红色向量既没有被拉伸又没有被压缩,其特征值为1。所有沿着垂直线的向量也都是特征向量,它们的特征值相等。它们构成这个特征值的特征空间。

求解特征值

非 \(\mathbf{0}\) 向量 \(\vec{\mathbf{v}}\) 是线性变化矩阵 \(\mathbf{A}\) 的特征向量,需要满足如下条件

eq: 2 »

\[det(\lambda \mathbf{I}_n - \underbrace{\mathbf{A}}_{n\times n}) = 0\]

其中,\(det\) 表示矩阵行列式,\(\lambda\) 是特征值,\(\mathbf{I}\) 是单位矩阵。

例如矩阵 \(\mathbf{A} = \begin{bmatrix}1 & 2 \\ 4 & 3\end{bmatrix}\) ,代入公式 2 得:

\[ \begin{align} det\left( \lambda \begin{bmatrix} 1 & 0 \\ 0 & 1 \end{bmatrix}-\begin{bmatrix} 1 & 2 \\ 4 & 3 \end{bmatrix} \right) &=0 \\ det\left( \begin{bmatrix} \lambda & 0 \\ 0 & \lambda \end{bmatrix}-\begin{bmatrix} 1 & 2 \\ 4 & 3 \end{bmatrix} \right) &=0 \\ det\left( \begin{bmatrix} \lambda -1 & -2 \\ -4 & \lambda -3 \end{bmatrix} \right) &=0 \end{align} \]

所以有:

\[\begin{align} (\lambda -1)(\lambda -3)-8 & =0 \\ \lambda ^{ 2 }-4\lambda -5 &=0 \\ (\lambda - 5)(\lambda +1) &= 0\end{align}\]

因此 \(\lambda\) 的值为 5 或者 -1 。

在 Python 中,可以使用 numpy.linalg.eigvals 方法求解一个方阵的特征值:

1
2
3
>>> a = np.matrix('1 2;4 3')
>>> print np.linalg.eigvals(a)
[-1. 5.]

前面说了变换矩阵必须是方阵,所以如果用在其他形状的矩阵上就会抛出 LinAlgError 错误:

1
2
3
4
5
6
7
8
9
>>> b = np.matrix('1 2 3;4 3 1')
>>> print np.linalg.eigvals(b)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "/usr/local/lib/python2.7/dist-packages/numpy/linalg/linalg.py", line 902, in eigvals
_assertNdSquareness(a)
File "/usr/local/lib/python2.7/dist-packages/numpy/linalg/linalg.py", line 212, in _assertNdSquareness
raise LinAlgError('Last 2 dimensions of the array must be square')
numpy.linalg.linalg.LinAlgError: Last 2 dimensions of the array must be square

求解特征向量

变换矩阵 \(\mathbf{A}\) 的特征空间(特征向量张成的空间)可以用下面的等式来求解:

eq: 3 »

\[\mathbf{E}_{\lambda}=N(\lambda I_n - \mathbf{A})\]

例如上面的变换矩阵 \(\mathbf{A} = \begin{bmatrix}1 & 2 \\ 4 & 3\end{bmatrix}\) ,代入公式 3 得:

\[{ E }_{ \lambda }=N\left( \lambda I_{ n }-\begin{bmatrix} 1 & 2 \\ 4 & 3 \end{bmatrix} \right) =N\left( \lambda \begin{bmatrix} 1 & 0 \\ 0 & 1 \end{bmatrix}-\begin{bmatrix} 1 & 2 \\ 4 & 3 \end{bmatrix} \right) =N\left( \begin{bmatrix} \lambda -1 & -2 \\ -4 & \lambda -3 \end{bmatrix} \right) \]

当 \(\lambda = 5\) 时,

\[{ E }_{ 5 }=N\left( \begin{bmatrix} 4 & -2 \\ -4 & 2 \end{bmatrix} \right) \]

利用前面所学的 零空间的求解方法 ,得

\[{ E }_{ 5 }= span\left(\begin{bmatrix}\frac{1}{2} \\ 1 \end{bmatrix}\right) \]

同样地,当 \(\lambda = -1\) 时,

\[{ E }_{ -1 }= span\left(\begin{bmatrix}1 \\ -1 \end{bmatrix}\right) \]

在 Python 中,可以使用 numpy.linalg.eig 方法来求解方阵的特征值和特征向量:

1
2
3
4
>>> a = np.matrix('1 2;4 3')
>>> print np.linalg.eig(a)
(array([-1., 5.]), matrix([[-0.70710678, -0.4472136 ],
[ 0.70710678, -0.89442719]]))

得到的元组中,第一部分是特征值,和前面使用 numpy.linalg.eigvals 得到的结果完全一样;第二部分是特征向量,乍一看好像和我们上面求解的结果不一样,但如果我们这么写就完全一样了:\(\begin{bmatrix}-0.70710678\begin{bmatrix}1 \\ -1\end{bmatrix} & -0.89442719\begin{bmatrix}\frac{1}{2} \\ 1\end{bmatrix} \end{bmatrix}\)

变换矩阵线性无关的特征向量特别适合作为空间的基,因为在这些方向上变换矩阵可以拉伸向量而不必扭曲和旋转它,使得计算大为简单。我们把这种基称为 特征基


  1. 逆矩阵的几种求法与解析

  2. TextRank: Bring Order Into Texts

  3. \(\mathbb{R}^{n}\) :表示 n 个有序实数二元组构成的空间。例如 \(\mathbb{R}^2\) 表示有序实数二元组 \((x_1, x_2)\) 构成的空间,即\(\mathbb{R}^n = \left\{ (x_1, \ldots, x_n) | x_1, \ldots, x_n \in \mathbb{R} \right\}\) 。

  4. 从历史的角度讲,该不等式应当称为Cauchy-Buniakowsky-Schwarz不等式【柯西-布尼亚科夫斯基-施瓦茨不等式】,因为,正是后两位数学家彼此独立地在积分学中推而广之,才将这一不等式应用到近乎完善的地步。

  5. 证明过程视频:http://open.163.com/movie/2011/6/E/M/M82ICR1D9_M83HEAPEM.html

  6. Building High-level Features Using Large Scale Unsupervised Learning