https://zhuanlan.zhihu.com/p/84415000
0. 為什么要用QR分解
的問題可以分成3類:
- 情況1:A是方陣,m=n
- 情況2:A是over-determined的,m>n
- 情況3:A是under-determined的,m<n
在[數值計算] 條件數的例子2里,遇到的情況1(A是方陣),通過構造拉格朗日插值來使得對A求逆足夠穩定。對於一般的情況下,解決思路是使用LU(LUP)分解來解決穩定性問題,在前一篇文中已經簡介過了[數值計算] LU分解、LUP分解、Cholesky分解。
對於后兩種情況, [數值計算] 數據擬合——線性最小二乘法 分析了用正規方程組求解over-determined以及under-determined的問題。但在文中也提到了,對於over-determined的線性最小二乘問題,正規方程組是不穩定的,通常需要用QR分解來處理:
理論很美好,在小數據量的時候沒問題,然而直接使用正規方程組求解會在數據量大(e.g. data size > 100)的時候不穩定numerically unstable。原因是 需要對求逆,而A我們都知道是Vandermonde矩陣的一部分,本身就是poorly conditioned,而
只會更糟糕。解決的方法是使用QR分解,這也是Python MATLAB求解 線性最小二乘 問題的方法。
1. QR分解
1.1 定義
一個矩陣
可以被分解成
,其中:
是正交矩陣![[公式]](/image/aHR0cHM6Ly93d3cuemhpaHUuY29tL2VxdWF0aW9uP3RleD1SKyU1Q2VxdWl2KyslNUNiZWdpbiU3QmJtYXRyaXglN0QrJTVDaGF0JTdCUiU3RCslNUMlNUMrMCslNUNlbmQlN0JibWF0cml4JTdEKyU1Q2luKyU1Q21hdGhiYiU3QlIlN0QlNUUlN0JtJTVDdGltZXMrbiU3RA==.png)
是上三角矩陣
1.2 正交矩陣的性質
![[公式]](/image/aHR0cHM6Ly93d3cuemhpaHUuY29tL2VxdWF0aW9uP3RleD1RJTVFVCtRKyUzRCtRUSU1RVQlM0RJ.png)
- 左乘一個正交矩陣對歐式范數的結果不影響(在下面證明eq.2的時候會用到)
![[公式]](/image/aHR0cHM6Ly93d3cuemhpaHUuY29tL2VxdWF0aW9uP3RleD0lN0MlN0MrUXYrJTdDJTdDXzIlNUUyKyUzRCt2JTVFVFElNUVUUXYrJTNEK3YlNUVUdislM0QrJTdDJTdDK3YrJTdDJTdDXzIlNUUyKyU1Q3RhZyU3QjElN0Q=.png)
1.3 從QR分解角度看線性最小二乘
對於一個over-determined線性最小二乘問題
,其目標函數是 ![[公式]](/image/aHR0cHM6Ly93d3cuemhpaHUuY29tL2VxdWF0aW9uP3RleD0lNUNiZWdpbiU3QmFsaWduJTdEKyU1Q3BoaSUyOHglMjkrJTNEKyU3QyU3QytyJTI4eCUyOSslN0MlN0NfMiU1RTIrJTI2JTNEKyU3QyU3QytiKy0rQXgrJTdDJTdDXzIlNUUyKyUzRCslN0MlN0MrYistK1ElNUNiZWdpbiU3QmJtYXRyaXglN0QlNUNoYXQlN0JSJTdEKyU1QyU1QyswJTVDZW5kJTdCYm1hdHJpeCU3RCt4KyU3QyU3Q18yJTVFMislNUMlNUMrJTI2JTNEKyU3QyU3QytRJTVFVCslMjhiKy0rUSU1Q2JlZ2luJTdCYm1hdHJpeCU3RCU1Q2hhdCU3QlIlN0QrJTVDJTVDKzAlNUNlbmQlN0JibWF0cml4JTdEK3glMjkrJTdDJTdDXzIlNUUyKyU1QyU1QyslMjYlM0QrJTdDJTdDK1ElNUVUYistKyU1Q2JlZ2luJTdCYm1hdHJpeCU3RCU1Q2hhdCU3QlIlN0QrJTVDJTVDKzAlNUNlbmQlN0JibWF0cml4JTdEK3grJTdDJTdDXzIlNUUyKyU1Q2VuZCU3QmFsaWduJTdEKyU1Q3RhZyU3QjIlN0Q=.png)
這里
,
,
,
。
如果把
拆分成上下兩部分,形式
類似,
。那么目標函數可以寫成下面的形式:
![[公式]](/image/aHR0cHM6Ly93d3cuemhpaHUuY29tL2VxdWF0aW9uP3RleD0lN0MlN0MrciUyOHglMjkrJTdDJTdDXzIlNUUyKyUzRCslN0MlN0MrY18xKy0rJTVDaGF0JTdCUiU3RHgrJTdDJTdDXzIlNUUyKyUyQislN0MlN0MrY18yJTdDJTdDXzIlNUUyKyU1Q3RhZyU3QjMlN0Q=.png)
可以看到,我們只能最小化前一部分
到0,即
,
的最小值為
。這樣處理之后就避免了求正規方程組中的
,避免了條件數變成
,所以QR分解法更加數值穩定。
1.4 計算QR分解的方法
一共有三種:
- Gram–Schmidt Orthogonalization
- Householder Triangularization
- Givens Rotations
1.5 Gram–Schmidt Orthogonalization
1.5.1 Reduced QR分解
GSO構建正交矩陣
的方法是從A矩陣的n個列(
)中構建互相正交的基,先選定
為第一個基,然后把第二列
減去平行於
的部分,剩下的垂直於
的部分作為下一個基,以此類推,直到生成了n個基。
![[公式]](/image/aHR0cHM6Ly93d3cuemhpaHUuY29tL2VxdWF0aW9uP3RleD0lNUNiZWdpbiU3QmFsaWduZWQlN0QrQV8lN0IlM0ElMkMwJTdEKyUyNiUzRCtyXyU3QjAwJTdEcV8wKyU1QyU1QytBXyU3QiUzQSUyQzElN0QrJTI2JTNEK3JfJTdCMCUyQzElN0RxXzArJTJCK3JfJTdCMSUyQzElN0RxXzErJTVDJTVDKyU1Q3Zkb3RzJTVDJTVDK0FfJTdCJTNBJTJDbi0xJTdEKyUyNiUzRCtyXyU3QjAlMkNuLTElN0RxXzArJTJCK3JfJTdCMSUyQ24tMSU3RHFfMSslMkIrJTVDZG90cyslMkIrcl8lN0JuLTElMkNuLTElN0RxXyU3Qm4tMSU3RCU1QyU1QytBKyUyNiUzRCslNUNoYXQlN0JRJTdEJTVDaGF0JTdCUiU3RCslNUNlbmQlN0JhbGlnbmVkJTdEKyU1Q3RhZyU3QjQlN0Q=.png)
![[公式]](/image/aHR0cHM6Ly93d3cuemhpaHUuY29tL2VxdWF0aW9uP3RleD0rJTVDYmVnaW4lN0JibWF0cml4JTdEK0FfJTdCJTNBJTJDMCU3RCslN0MrQV8lN0IlM0ElMkMxJTdEKyU3QyslNUNkb3RzKyU3QytBXyU3QiUzQSUyQ24tMSU3RCsrJTVDZW5kJTdCYm1hdHJpeCU3RCslM0QrJTVDYmVnaW4lN0JibWF0cml4JTdEK3FfJTdCMCU3RCslN0MrcV8lN0IxJTdEKyU3QyslNUNkb3RzKyU3QytxXyU3Qm4tMSU3RCsrJTVDZW5kJTdCYm1hdHJpeCU3RCsrJTVDYmVnaW4lN0JibWF0cml4JTdEK3JfJTdCMCUyQzAlN0QrJTI2K3JfJTdCMCUyQzElN0QrJTI2KyU1Q2RvdHMrJTI2K3JfJTdCMCUyQ24tMSU3RCU1QyU1QysrJTI2K3JfJTdCMSUyQzElN0QrJTI2KyU1Q2RvdHMrJTI2K3JfJTdCMSUyQ24tMSU3RCU1QyU1QysrJTI2KyUyNislNUNkZG90cyslMjYrJTVDdmRvdHMrJTVDJTVDKyslMjYrJTI2KyUyNityXyU3Qm4tMSUyQ24tMSU3RCU1QyU1QyslNUNlbmQlN0JibWF0cml4JTdEJTVDJTVDKyslNUN0YWclN0I1JTdE.png)
這個方法生成的
,
,和section1.1中定義的Q是方陣,R不是方陣有區別。這個結果被稱為Reduced QR分解,因為m>n,所以只滿足
,而不滿足
。
Credit to http://iacs-courses.seas.harvard.edu/courses/am205/schedule/
Reduced QR分解同樣可以求解over-determined線性最小二乘問題。形式類似Full QR分解:
![[公式]](/image/aHR0cHM6Ly93d3cuemhpaHUuY29tL2VxdWF0aW9uP3RleD0lNUNoYXQlN0JSJTdEeCslM0QrJTVDaGF0JTdCUSU3RCU1RVQrYislNUN0YWclN0I2JTdE.png)
其中
,
。
1.5.2 Full QR分解
為了實現定義中的完整的QR分解,需要把上面生成Q中的n個基拓展成m個互相正交的基。但此處並沒有對額外的m-n個基的順序有特殊要求,因此任意一種順序都可以。另外還需要把
下面加m-n行零矩陣。
在Python中,Reduced QR分解和Full QR分解對應於
q,r = np.linalg.qr(A) # reduced q,r = np.linalg.qr(A,mode="complete") # full
1.5.3 Classic Gram–Schmidt Orthogonalization算法 CGSO
觀察Eq.4可以發現,其實每一步迭代都只有一個
未知:左邊
已知,右邊
已知, q的系數們
可以用公式
求得。把
代入Eq.4,並整理可得
![[公式]](/image/aHR0cHM6Ly93d3cuemhpaHUuY29tL2VxdWF0aW9uP3RleD1yXyU3QmolMkNqJTdEcV8lN0JqJTdEKyUzRCt2X2olM0QrQV8lN0IlM0ElMkNqJTdEKy0rJTI4cV8wJTVFVCtBXyU3QiUzQSUyQ2olN0QlMjlxXzArLSslMjhxXzElNUVUK0FfJTdCJTNBJTJDaiU3RCUyOXFfMSstKyU1Q2RvdHMrJTI4cV8lN0JqLTElN0QlNUVUK0FfJTdCJTNBJTJDaiU3RCUyOXFfJTdCai0xJTdEKyU1Q3RhZyU3QjclN0Q=.png)
因此
,
。其中,
的符號不確定是因為,任意一個基方向反向之后,這個QR分解不會有任何問題,這個基仍然和其他基正交。為了計算方便,這里就規定
。
整理上面計算
和
的過程為算法的形式:
Credit to http://iacs-courses.seas.harvard.edu/courses/am205/schedule/
觀察算法過程,可以發現,唯一可能在理論上出問題的情況就是,出現某個
=0,導致在算法第8行出現0在分母上的情況。因此只要
是滿秩的,且每個
都>0,那么reduced QR分解的結果是唯一的。
1.5.4 Modified Gram–Schmidt Orthogonalization算法 MGSO
由於CGSO對舍入誤差很敏感,容易導致生成的基
的正交性隨着迭代越來越弱,因此引入改進的GSO。核心思想是,在每個
生成后,直接把A剩下的列(下面算法第7行)都去掉
的成分(下面算法的第8-9行)。因為只是把計算的順序變了,所以理論上計算結果是一樣的。
Credit to http://iacs-courses.seas.harvard.edu/courses/am205/schedule/
但是改進之后穩定性會好很多。從實際計算步驟上來看,CGSO和MGSO的區別在於,CGSO中,每次迭代新的一列
,計算每個
都是用的同一個
,而MGSO計算
的時候用的
是已經減去前面j-1個基的分量之后的
。
這樣做的好處是:誤差的傳遞是局部的。比如計算
是精確的,計算
出現誤差,即,
在
上存在一個微小分量。按照CGSO,接下來要分別計算
在
和
的分量,最終
;而MGSO則先計算
在
上的分量,去除掉這個分量之后成為
,再計算並去除
在
上的分量得到最終的
,此時如果計算是精確的,那么至少可以保證
。
直觀理解參考下面這張圖,在三維xyz坐標系里,
是帶誤差的
。用CGSO處理
的時候,
用的是初始值
,包含了
和
兩個方向的誤差,而用MGSO處理
的時候,
用的是去掉
分量之后的
,只有
方向的誤差。

公式上計算這些誤差參考The modified Gram-Schmidt procedure:
Credit to https://www.math.uci.edu/~ttrogdon/105A/html/Lecture23.html
1.6 Givens Rotations
1.6.1 Givens Rotation Matrix
![[公式]](/image/aHR0cHM6Ly93d3cuemhpaHUuY29tL2VxdWF0aW9uP3RleD1HJTI4aSUyQ2olMkMlNUN0aGV0YSUyOSslM0QrKyU1Q2JlZ2luJTdCYm1hdHJpeCU3RCsxKyUyNislNUNkb3RzKyUyNiswKyUyNislNUNkb3RzKyUyNiswKyUyNislNUNkb3RzKyUyNiswJTVDJTVDKyU1Q3Zkb3RzKyUyNislNUNkZG90cyslMjYrJTVDdmRvdHMrJTI2KyU1Q2Rkb3RzKyUyNislNUN2ZG90cyslMjYrJTVDZGRvdHMrJTI2KyU1Q3Zkb3RzJTVDJTVDKzArJTI2KyU1Q2RvdHMrJTI2K2NvcyU1Q3RoZXRhKyUyNislNUNkb3RzKyUyNitzaW4lNUN0aGV0YSslMjYrJTVDZG90cyslMjYrMCU1QyU1QyslNUN2ZG90cyslMjYrJTVDZGRvdHMrJTI2KyU1Q3Zkb3RzKyUyNislNUNkZG90cyslMjYrJTVDdmRvdHMrJTI2KyU1Q2Rkb3RzKyUyNislNUN2ZG90cyU1QyU1QyswKyUyNislNUNkb3RzKyUyNistc2luJTVDdGhldGErJTI2KyU1Q2RvdHMrJTI2K2NvcyU1Q3RoZXRhKyUyNislNUNkb3RzKyUyNiswJTVDJTVDKyU1Q3Zkb3RzKyUyNislNUNkZG90cyslMjYrJTVDdmRvdHMrJTI2KyU1Q2Rkb3RzKyUyNislNUN2ZG90cyslMjYrJTVDZGRvdHMrJTI2KyU1Q3Zkb3RzJTVDJTVDKzArJTI2KyU1Q2RvdHMrJTI2KzArJTI2KyU1Q2RvdHMrJTI2KzArJTI2KyU1Q2RvdHMrJTI2KzElNUMlNUMrJTVDZW5kJTdCYm1hdHJpeCU3RCslNUN0YWclN0I4JTdE.png)
![[公式]](/image/aHR0cHM6Ly93d3cuemhpaHUuY29tL2VxdWF0aW9uP3RleD0lNUNiZWdpbiU3QmFsaWduZWQlN0QraSslMjYlM0MraislNUMlNUMrR18lN0JpJTJDaSU3RCslMjYlM0QrYyU1QyU1QytHXyU3QmolMkNqJTdEKyUyNiUzRCtjJTVDJTVDK0dfJTdCaSUyQ2olN0QrJTI2JTNEK3MlNUMlNUMrR18lN0JqJTJDaSU3RCslMjYlM0QrLXMlNUMlNUMrR18lN0JrJTJDayU3RCslMjYlM0QrMSUyQyU1Qytmb3IlNUMrayU1Q25lK2klNUMrb3IlNUMraiU1QyU1QytHXyU3QnQlMkNzJTdEKyUyNiUzRCswJTJDJTVDK290aGVyd2lzZSslNUNlbmQlN0JhbGlnbmVkJTdEKyU1Q3RhZyU3QjklN0Q=.png)
1.6.2 Givens Rotations的作用
對於一個矩陣
,對於第i列的第j和k行
,如果
元素不為0,可以通過一個Givens Rotation把它轉換成0。
![[公式]](/image/aHR0cHM6Ly93d3cuemhpaHUuY29tL2VxdWF0aW9uP3RleD0lNUNiZWdpbiU3QmJtYXRyaXglN0QrYyslMjYrcyU1QyU1QystcyslMjYrYyslNUNlbmQlN0JibWF0cml4JTdEKyU1Q2JlZ2luJTdCYm1hdHJpeCU3RCtBXyU3QmklMkNqJTdEJTVDJTVDK0FfJTdCaSUyQ2slN0QrJTVDZW5kJTdCYm1hdHJpeCU3RCslM0QrJTVDYmVnaW4lN0JibWF0cml4JTdEKyU1Q2FscGhhJTVDJTVDKzArJTVDZW5kJTdCYm1hdHJpeCU3RCU1QyU1QyslNUNhbHBoYSslM0QrJTVDc3FydCU3QkFfJTdCaSUyQ2olN0QlNUUyKyUyQitBXyU3QmklMkNrJTdEJTVFMislN0QlNUMlNUMrYyslM0QrJTVDZnJhYyU3QkFfJTdCaSUyQ2olN0QlN0QlN0IlNUNhbHBoYSU3RCU1QyU1QytzKyUzRCslNUNmcmFjJTdCQV8lN0JpJTJDayU3RCU3RCU3QiU1Q2FscGhhJTdEJTVDJTVDKyU1Q3RhZyU3QjEwJTdEKw==.png)
當
或者
很小或者很大,且它們的平方不是用float表示的時候,對它們求平方會導致上溢出或者下溢出。因此更好的公式是:
- 如果
,那么設 ![[公式]](/image/aHR0cHM6Ly93d3cuemhpaHUuY29tL2VxdWF0aW9uP3RleD10KyUzRCtBXyU3QmklMkNrJTdEJTJGQV8lN0JpJTJDaiU3RA==.png)
![[公式]](/image/aHR0cHM6Ly93d3cuemhpaHUuY29tL2VxdWF0aW9uP3RleD1jKyUzRCslNUNmcmFjJTdCMSU3RCU3QiU1Q3NxcnQlN0IxJTJCdCU1RTIlN0QlN0QlMkMlNUMrcyslM0QrY3Q=.png)
- 如果
,那么設 ![[公式]](/image/aHR0cHM6Ly93d3cuemhpaHUuY29tL2VxdWF0aW9uP3RleD0lNUN0YXUrJTNEK0FfJTdCaSUyQ2olN0QlMkZBXyU3QmklMkNrJTdEKw==.png)
![[公式]](/image/aHR0cHM6Ly93d3cuemhpaHUuY29tL2VxdWF0aW9uP3RleD1zKyUzRCslNUNmcmFjJTdCMSU3RCU3QiU1Q3NxcnQlN0IxJTJCJTVDdGF1JTVFMiU3RCU3RCUyQyU1QytjKyUzRCtzJTVDdGF1.png)
不過這個問題基本只有在設計package造輪子的時候才會遇到,所以通常用Eq.10不會引起問題。詳見Scientific Computing - Heath的第128頁。
另外,在涉及反三角的數值運算的時候,建議使用atan2替代atan,范圍更大,更穩定。例如atan2(y,x)會返回一個(x,y)向量和正x軸的夾角。
the difference between atan and atan2 in C++?wikipedia Atan2
1.6.3 Givens Rotations 算法
對於一個稠密的矩陣
,逐漸把A消元成R(參考1.5.1的full QR的圖)。
Credit to http://iacs-courses.seas.harvard.edu/courses/am205/schedule/
注意第三行的循環,j是從大到小的迭代。
1.6.4 Givens Rotations 優勢
當A是稠密矩陣,Givens Rotations並沒有比另外兩種算法更高效,但如果A是稀疏矩陣,那么Givens Rotations大小為0的元素可以直接被忽略。另一個優勢是,Givens Rotations更容易並行化,因為Givens Rotations只對兩個元素進行操作,處理不同列的時候可以完全的獨立。

求逆,而A我們都知道是Vandermonde矩陣的一部分,本身就是poorly conditioned,而
