计算 QR 分解

archive time: 2024-12-23

记录一下计算过程,防止之后想要重构的时候不会算

缘起

为什么会有这么一篇记录呢?

最主要的就是为自己留一个思路备份,防止之后如果自己又想要实现 QR 分解,不知道如何计算, 同时也是让自己在记录的时候理一下思路,对于计算的过程更加清楚

QR 分解

那么什么是 QR 分解呢?

对于一个维数为 的矩阵 ,如果这个矩阵的列向量 是两两线性无关的, 这要求这个矩阵的应该是一个高矩阵或者是方阵,即 , 那么我们可以说这个矩阵可以通过某些方法得到 ,其中 ,而 是一个上三角矩阵1

由于 是上三角矩阵,对于位于 列的元素,如果 ,那么 , 则对于 的列向量 ,可以用 的列向量 的元素来表示,即:

这个“某些方法”有很多,不过常见的方法只有三种,那就是 Gram-Schmidt 过程Householder 方法 以及 Givens 旋转

但是由于 Givens 旋转只在相对较少的非对角线元素为零的时候比较有用,通常我们只会使用 Gram-Schmidt 过程 和 Householder 方法

Gram-Schmidt 过程

Gram-Schmidt 过程计算是相对简单的,不过因此也是相对数值不稳定的2,整个计算大概可以分成 步:

  1. 将原矩阵 拆分成列向量表示,即
  2. 我们有辅助向量 ,其中 ,对于
  3. 对应的,我们可以对其归一化,即
  4. 那么 或者

其中对于辅助向量 的计算是误差的关键, 所以就有了 MGS,即修正 Gram-Schmidt 过程, 将计算 的过程展开为了:

这样可以有效的减少计算误差

Householder 方法

Householder 方法的 QR 分解主要是靠 Householder 变换, 即对于某个已经归一化的向量 ,我们可以有:

其中 的共轭转置,也可表示为 ,对于实向量,等价为转置,即

对于计算出来的这个 我们称为 Householder 矩阵,而这个过程就是 Householder 变换

这个 Householder 矩阵有非常多的性质,其中非常重要的就是这个矩阵是自反矩阵,即

具体的 QR 分解的步骤如下:

  1. 先令 ,然后取 的第 ,并且令取出来的列向量中位置 的元素都为 得到
  2. 然后让 的第 位加上自身的模 乘以 符号数3,记为
  3. 进行 Householder 变换,即
  4. ,其中对于纬度为 的矩阵

整个计算过程相对 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 一般在 的时候用于表示该矩阵对应的齐次解对应的解空间,那么该如何计算呢?

其实还是比较简单的,也不用待定系数,通过比较就可以计算:

  1. 将矩阵化简成行最简形式,如果是满秩矩阵,那么 Nullspace 就是空集,否则就继续运算
  2. 记录每一行第一个不为零的元素的列数,所有的列数一起记为
  3. 我们可以依次按列检查 并设置对应向量
  4. 对应向量的元素中,如果位置属于 ,对应元素取反,位置等于自身列数,记为 ,其他位置记为
  5. 将所有向量集合就是对应 Nullspace

例子

假如我们有矩阵:

要求这个矩阵的 Nullspace,首先将其化简为行最简形式:

我们可以标记第一列为第一行首个非零元素,第三列为第二行首个非零元素, 那么 ,对应

首先检查第二列,对应向量初始化为 , 第一列属于 ,并且对应第一行,那么第一个元素就是第二列第一行的元素的相反数, 向量变成 ,第二列是自身,那么对应位置设为 , 第四列和第五列是其他位置,设置为 ,第三列属于 ,且对应第二行,那么第三个元素就是第二列第二行元素的相反数, 综合下来,第二列对应的向量就是

然后是第四列,第一个元素对应第四列第一行元素的相反数,第二个和第五个元素是其他位置,设为 , 第三个元素对应第四列第二行元素的相反数,最后第四个元素是自身,设为 , 综合下来第四列对应向量就是

第五列也是一样的流程,第一个和第三个元素分别对应第五列第一行和第二行元素的相反数,第二个和第四个元素是其他位置,设为 , 第五个元素是自身,设为 ,即

那么这个矩阵 对应的 Nullspace 就是:

后记

整体实现的难度不是很大,按照步骤一步步实现即可,但是对于细节的处理还是需要多注意, 例如 Householder 方法中,究竟是加上 模 与 符号数 的乘积,还是减去,这个有一个取舍, 对于浮点数实现,一般是使用加上,从而避免得到 NaN

还有就是对于这两种分解背后的方法,即 Gram-Schimdt 正交化和 Householder 变换, 对于其几何解释的理解也是难点之一


1

BOYD S, VANDENBERGEHE L. 应用线性代数:向量、矩阵及最小二乘[M]. 张文博, 张丽静, 译. 北京: 机械工业出版社, 2020.8: 163[2024-12-22]

2

Gram–Schmidt 过程.Wikipedia [DB/OL].(2024-11-26)[2024-12-22]. https://en.wikipedia.org/wiki/Gram%E2%80%93Schmidt_process#Numerical_stability

3

对于实数,符号数对于正数就是 ,负数就是 ,零就是 ,而对于复数,符号数就是对其归一化的值,即

4

零空间.Wikipedia [DB/OL].(2024-12-4)[2024-12-23]. https://en.wikipedia.org/wiki/Kernel_(linear_algebra)