计算 QR 分解
archive time: 2024-12-23
记录一下计算过程,防止之后想要重构的时候不会算
缘起
为什么会有这么一篇记录呢?
最主要的就是为自己留一个思路备份,防止之后如果自己又想要实现 QR 分解,不知道如何计算, 同时也是让自己在记录的时候理一下思路,对于计算的过程更加清楚
QR 分解
那么什么是 QR 分解呢?
对于一个维数为 的矩阵 ,如果这个矩阵的列向量 是两两线性无关的, 这要求这个矩阵的应该是一个高矩阵或者是方阵,即 , 那么我们可以说这个矩阵可以通过某些方法得到 ,其中 ,而 是一个上三角矩阵1
由于 是上三角矩阵,对于位于 行 列的元素,如果 ,那么 , 则对于 的列向量 ,可以用 的列向量 和 的元素来表示,即:
这个“某些方法”有很多,不过常见的方法只有三种,那就是 Gram-Schmidt 过程,Householder 方法 以及 Givens 旋转
但是由于 Givens 旋转只在相对较少的非对角线元素为零的时候比较有用,通常我们只会使用 Gram-Schmidt 过程 和 Householder 方法
Gram-Schmidt 过程
Gram-Schmidt 过程计算是相对简单的,不过因此也是相对数值不稳定的2,整个计算大概可以分成 步:
- 将原矩阵 拆分成列向量表示,即
- 我们有辅助向量 ,其中 ,对于 ,
- 对应的,我们可以对其归一化,即
- 那么 , 或者
其中对于辅助向量 的计算是误差的关键, 所以就有了 MGS,即修正 Gram-Schmidt 过程, 将计算 的过程展开为了:
这样可以有效的减少计算误差
Householder 方法
Householder 方法的 QR 分解主要是靠 Householder 变换, 即对于某个已经归一化的向量 ,我们可以有:
其中 是 的共轭转置,也可表示为 ,对于实向量,等价为转置,即
对于计算出来的这个 我们称为 Householder 矩阵,而这个过程就是 Householder 变换
这个 Householder 矩阵有非常多的性质,其中非常重要的就是这个矩阵是自反矩阵,即
具体的 QR 分解的步骤如下:
- 先令 ,然后取 的第 列 ,并且令取出来的列向量中位置 的元素都为 得到
- 然后让 的第 位加上自身的模 乘以 符号数3,记为
- 对 进行 Householder 变换,即
- 则 ,其中对于纬度为 的矩阵 ,
整个计算过程相对 Gram-Schmidt 过程要复杂一点,但是通过对 的处理得到 ,可以尽可能保证计算的精度,即有一定的数值稳定性
更进一步,对于高矩阵, 通常会有部分行为 ,对此我们可以进行消减, 即对于 的矩阵 ,我们可以仅保留 的前 列和 的前 行
Gram-Schmidt 过程 和 Householder 方法的比较
QR 分解是不唯一的,即你使用不同方法得到的矩阵 和 也大概率是不一样的,特别是维度
对于 的矩阵 , Gram-Schmidt 过程得到的 是 的,而 是 的, 不过 Householder 方法得到的 是 的,而 是 的,
但是通过优化,即舍去“多余”部分,我们可以得到与 Gram-Schmidt 过程的结果维度接近的 和
Givens 旋转过程
使用 Givens 旋转来计算 QR 分解,实际上就是利用 Givens 旋转矩阵来将特定的位置变成零,从而构造出一个上三角矩阵, 一般这个过程是按照列来进行的,即先将 变成零,然后 ,直到将第一列第 到 行元素变为零, 第二列也是如此,直到将第二列第 到 行的元素也就是主对角线下的元素变成零
而这一系列的构造过程中,也就是这些 Givens 旋转矩阵的乘积就是我们的 , 所以 Givens 旋转计算 QR 分解的关键就是构造 Givens 旋转矩阵
假设我想要将 的矩阵 的 行 列元素 变成零,通常做法是使用其上一行元素即 进行消元
Givens 旋转矩阵是基于单位矩阵的,所以我们可以先构造一个 的单位矩阵称为
既然被称为旋转矩阵,那么自然是有“转”的部分的,令要被消元的元素为 ,辅助消元的元素为 , 那么对应旋转的半径就是这两个元素构成向量的模长,即 , 那么对应的 ,
那么对应例子中的 Givens 旋转矩阵只需要将 的 和 元素设置为 , 设置为 ,而 设置为 , 这样,一个合适的 Givens 旋转矩阵就构造好了,即:
附记:Nullspace 计算
这边再来记录一下如何计算 Nullspace
Nullspace 又称为 Kernel 或者零空间,其在矩阵中的定义为:
其中 是一个 的矩阵, 是一个长度为 的向量4
Nullspace 一般在 的时候用于表示该矩阵对应的齐次解对应的解空间,那么该如何计算呢?
其实还是比较简单的,也不用待定系数,通过比较就可以计算:
- 将矩阵化简成行最简形式,如果是满秩矩阵,那么 Nullspace 就是空集,否则就继续运算
- 记录每一行第一个不为零的元素的列数,所有的列数一起记为
- 我们可以依次按列检查 并设置对应向量
- 对应向量的元素中,如果位置属于 ,对应元素取反,位置等于自身列数,记为 ,其他位置记为
- 将所有向量集合就是对应 Nullspace
例子
假如我们有矩阵:
要求这个矩阵的 Nullspace,首先将其化简为行最简形式:
我们可以标记第一列为第一行首个非零元素,第三列为第二行首个非零元素, 那么 ,对应
首先检查第二列,对应向量初始化为 , 第一列属于 ,并且对应第一行,那么第一个元素就是第二列第一行的元素的相反数, 向量变成 ,第二列是自身,那么对应位置设为 , 第四列和第五列是其他位置,设置为 ,第三列属于 ,且对应第二行,那么第三个元素就是第二列第二行元素的相反数, 综合下来,第二列对应的向量就是
然后是第四列,第一个元素对应第四列第一行元素的相反数,第二个和第五个元素是其他位置,设为 , 第三个元素对应第四列第二行元素的相反数,最后第四个元素是自身,设为 , 综合下来第四列对应向量就是
第五列也是一样的流程,第一个和第三个元素分别对应第五列第一行和第二行元素的相反数,第二个和第四个元素是其他位置,设为 , 第五个元素是自身,设为 ,即
那么这个矩阵 对应的 Nullspace 就是:
后记
整体实现的难度不是很大,按照步骤一步步实现即可,但是对于细节的处理还是需要多注意,
例如 Householder 方法中,究竟是加上 模 与 符号数 的乘积,还是减去,这个有一个取舍,
对于浮点数实现,一般是使用加上,从而避免得到 NaN
还有就是对于这两种分解背后的方法,即 Gram-Schimdt 正交化和 Householder 变换, 对于其几何解释的理解也是难点之一
BOYD S, VANDENBERGEHE L. 应用线性代数:向量、矩阵及最小二乘[M]. 张文博, 张丽静, 译. 北京: 机械工业出版社, 2020.8: 163[2024-12-22]
Gram–Schmidt 过程.Wikipedia [DB/OL].(2024-11-26)[2024-12-22]. https://en.wikipedia.org/wiki/Gram%E2%80%93Schmidt_process#Numerical_stability
对于实数,符号数对于正数就是 ,负数就是 ,零就是 ,而对于复数,符号数就是对其归一化的值,即
零空间.Wikipedia [DB/OL].(2024-12-4)[2024-12-23]. https://en.wikipedia.org/wiki/Kernel_(linear_algebra)