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 定義
一個矩陣 可以被分解成
,其中:
是正交矩陣
是上三角矩陣
1.2 正交矩陣的性質
- 左乘一個正交矩陣對歐式范數的結果不影響(在下面證明eq.2的時候會用到)
1.3 從QR分解角度看線性最小二乘
對於一個over-determined線性最小二乘問題 ,其目標函數是
這里 ,
,
,
。
如果把 拆分成上下兩部分,形式
類似,
。那么目標函數可以寫成下面的形式:
可以看到,我們只能最小化前一部分 到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個基。
這個方法生成的 ,
,和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分解:
其中 ,
。
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,並整理可得
因此 ,
。其中,
的符號不確定是因為,任意一個基方向反向之后,這個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
1.6.2 Givens Rotations的作用
對於一個矩陣,對於第i列的第j和k行
,如果
元素不為0,可以通過一個Givens Rotation把它轉換成0。
當 或者
很小或者很大,且它們的平方不是用float表示的時候,對它們求平方會導致上溢出或者下溢出。因此更好的公式是:
- 如果
,那么設
- 如果
,那么設
不過這個問題基本只有在設計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只對兩個元素進行操作,處理不同列的時候可以完全的獨立。