高斯有研究矩阵分解?
你可能会说: 我知道,高斯消元法可以用矩阵乘积的形式来表示,相当于对方程组的系数矩阵 作 分解。
是可以这么说,但这毕竟是后人的观点。本文并不是指 分解,而是想说说由另一个主题引出的矩阵分解。
高斯消元法是为了求解线性方程组而生的,但是,它也可以拿来计算二次型的标准型,即对称矩阵对角化。
关于二次型与标准型的知识,可以阅读下面这篇。
二次型和矩阵合同原来是这么一回事高斯那会儿还没有矩阵的概念,更没有矩阵的运算。但为了让过程简洁清晰,我们还是使用矩阵的语言来描述和证明高斯的二次型标准化方法 (对角化对称矩阵)。本文就是为了将这个过程清晰地展现出来,让大家分分钟就能整明白。对,我们的目标就是: 只花几分钟,知识、方法带回家。
1高斯与二次型
矩阵分解法是随着行列式、线性方程组,尤其是双线性形式和二次型等问题的研究而逐渐显现出来的。
拉格朗日、高斯和雅可比等可以说是做了一些早期工作。
大概是为了计算二次型的极值,拉格朗日在 1759 年提出了所谓的配方法,用现在的话说就是构造以三角矩阵表示的线性变换来实现对二次型的标准化处理。
例如,可以用如下方式来将一个二元二次型转化为标准型,
其中, 为系数矩阵的 阶顺序主子式,以及
好家伙,又发现行列式的身影了。
拉格朗日并没有处理 元一般情况,后来雅可比在 1834 年左右推广了上面方法,有些资料将其称为雅可比公式。
本文主要看高斯的工作,他在 1823 年撰写的手稿中使用他早在 1801 年就使用的消元法来实现将一般二次型转化为标准型的任务(也有一说认为,高斯是在拉格朗日方法的启发下实现最小二乘法,这确实也是一个二次型的极值问题)。
这里我们用高斯的符号来书写。具体而言,可以将函数 (关于 的一个二次型)简化为以下形式:
其中,除数 等是常数,而 等是 等的线性函数。但是,第二个函数 独立于 ;第三个 独立于 和 ;第四个 独立于 和 ,依此类推。最后一个函数 仅取决于最后一个未知数。此外,系数 在 中分别乘以 。
从中我们可以看到高斯这里的方法将二次型 的矩阵分解为乘积 ,其中 是对角矩阵,而 是与 具有相同对角元素的上三角矩阵。
高斯这里的 等函数是向量 对应的元素。
值得注意的是,说它们是矩阵分解,肯定是以后人的眼光来看待这些工作。
2推导
接下来我们用矩阵运算那一套来证明高斯的对角化方法。
首先,我们知道通过左乘一系列初等矩阵的乘积 ,可以将矩阵 转化为一个上三角矩阵 ,
由于矩阵是对称的,再右乘矩阵 的转置,相当于对矩阵作了列的初等变换,最终可以将矩阵转化为对角矩阵。
于是,我们就得到了矩阵 的如下分解,
注意,这里的矩阵 只是上三角矩阵,并不是正交矩阵。
验证
由式 得 ,由式 可得 ,将它们代入式 ,得
上式中红色框框里的矩阵刚好消去了,最后再根据矩阵 是对称的,验证通过。
当然,这种方法依赖高斯消元,那么消元法的弊端也可能会遇到,即在消元过程中碰到对角元素为零的情况。
下面,我们对式 作进一步说明。
我们知道,高斯消元的过程相当于对矩阵 不停地左乘初等矩阵。
先构造如下初等矩阵,
对系数矩阵左乘该初等矩阵,对第 2 行首个元素进行消元,
由于矩阵 是对称的,即 。此时如果对上面结果再右乘 ,相当于对列作初等变换,可得对称矩阵,
对第 1 列和第 1 行继续消元,得
接下来除去首行和首列,是不是变成一个 对称矩阵啦。
两边继续左右开弓,最后得到对角矩阵 ,
把所有初等矩阵乘起来得到矩阵 ,于是得到式 ,
二次型的标准化
高斯这里的方法本来就是为了对二次型作标准化处理。现在已经有了如下分解,
则对应的二次型为,
于是找到了变量代换,即 ,实现了对二次型的标准化处理。对,这就是高斯论文里做的事情。
程序小实验
下面我用 NumPy 做个实验来实际感受一番。
import numpy
# 生成一个对称矩阵
array([[8, 1, 3],
[1, 8, 5],
[3, 5, 2]])
3)
array([[ 1. , 0. , 0. ],
[-0.125, 1. , 0. ],
[ 0. , 0. , 1. ]])
P1@A
array([[8. , 1. , 3. ],
[0. , 7.875, 4.625],
[3. , 5. , 2. ]])
A@P1.T
array([[8. , 0. , 3. ],
[1. , 7.875, 5. ],
[3. , 4.625, 2. ]])
用 P1 左右开弓,是不是消元的同时将 A 转化为另一个对称矩阵啦。
P1@A@P1.T
array([[8. , 0. , 3. ],
[0. , 7.875, 4.625],
[3. , 4.625, 2. ]])
3)
array([[ 1. , 0. , 0. ],
[ 0. , 1. , 0. ],
[-0.375, 0. , 1. ]])
P2@A
array([[8. , 1. , 3. ],
[1. , 8. , 5. ],
[0. , 4.625, 0.875]])
P2@P1@A
array([[8. , 1. , 3. ],
[0. , 7.875, 4.625],
[0. , 4.625, 0.875]])
A@P1.T@P2.T
array([[8. , 0. , 0. ],
[1. , 7.875, 4.625],
[3. , 4.625, 0.875]])
A1 = P2@P1@A@P1.T@P2.T
A1
array([[8. , 0. , 0. ],
[0. , 7.875, 4.625],
[0. , 4.625, 0.875]])
3)
array([[ 1. , 0. , 0. ],
[ 0. , 1. , 0. ],
[ 0. , -0.58730159, 1. ]])
P3@A1
array([[ 8. , 0. , 0. ],
[ 0. , 7.875 , 4.625 ],
[ 0. , 0. , -1.84126984]])
D = P3@A1@P3.T
D
array([[ 8. , 0. , 0. ],
[ 0. , 7.875 , 0. ],
[ 0. , 0. , -1.84126984]])
U = P3@P2@P1@A
U
array([[ 8. , 1. , 3. ],
[ 0. , 7.875 , 4.625 ],
[ 0. , 0. , -1.84126984]])
D_inv = np.linalg.inv(D)
U.T@D_inv@U
array([[8., 1., 3.],
[1., 8., 5.],
[3., 5., 2.]])
A
array([[8, 1, 3],
[1, 8, 5],
[3, 5, 2]])
注意,这里的上三角矩阵并不是正交矩阵。U.T@U
array([[64. , 8. , 24. ],
[ 8. , 63.015625 , 39.421875 ],
[24. , 39.421875 , 33.78089963]])
与其他分解的关系
我们知道,对称矩阵可以通过它的特征值和特征向量来对角化,与本文介绍的这种分解方法是不同的。它们的结果不同,需要的计算量也是不同的。
另外,这里的分解跟后来所谓的 LDL 分解十分相似,仅仅是上三角矩阵的对角元素和中间的对角矩阵取法有一点区别。看来这个方法又可以归功于高斯啊。但实际看貌似并没有这么命名,不清楚这里面的原因,或许高斯这篇论文并没有引起多少人关注吧。
下面的代码展示了对上面矩阵 作 LDL 分解后的结果。
from scipy
0]
array([[1. , 0. , 0. ],
[0.125 , 1. , 0. ],
[0.375 , 0.58730159, 1. ]])
1]
array([[ 8. , 0. , 0. ],
[ 0. , 7.875 , 0. ],
[ 0. , 0. , -1.84126984]])
0]@LD[
array([[8., 1., 3.],
[1., 8., 5.],
[3., 5., 2.]])
3小结
矩阵分解至少有两个方面的意义,
理论分析。矩阵分解可以用于进一步分析其他问题。这里更注重分解的意义以及在理论推导中的应用。
数值计算。一次分解,结果可以重复利用,从而大大降低计算量。这里更注重分解的效率与数值稳定性等问题。
除了批量解线性方程组的例子,我们再来看一个其他例子。
很多时候需要计算一个矩阵的 次幂,如
个相乘直接计算显然不划算,而且还可能会带来很大误差。但如果 可以对角化 ,那么有 。于是,
最后只需要计算对角阵的 n 次幂,计算量大大降低了。当然,本文中的分解结果中,是 ,而不是 ,因此并不适合上面的应用。
本文介绍了高斯利用消元法实现了二次型的标准化处理,从矩阵的角度看,恰恰就是对称矩阵的对角化以及分解。高斯这个分解方法的意义或许并不是很大,但可以说是非常早期的分解方法,对后续方法有一定启发作用。
矩阵分解对于矩阵的应用十分重要,本篇只是引子,更多精彩在后头。
相关阅读矩阵和线性代数原来是这么来的
概率论原来可以这样优雅地入门
机器学习的数学基础 之 向量范数
机器学习的数学基础 之 矩阵范数
矩阵前传 - 消元法与行列式之独立演义
矩阵前传 - 牛顿没带红的货被高斯带红了
矩阵前传 - 克莱姆没能证明的法则被他两行搞定矩阵前传 - 矩阵之父 Sylvester 为什么提出 Matrix矩阵前传 - 柯西-比内公式及其用初等矩阵的证明二次型和矩阵合同原来是这么一回事拉格朗日乘子法的来历与直观解释
矩阵特征值是这么来的,以及有趣的盖尔圆万能的 SVD 分解是哪位牛人提出来的?