最近一直work on locally weighted least-square
結果發現使用gausvar
這個kernel的時候,weight會出現負的
我原本的解法是直接在input跟output都乘上根號的weight
結果這招就行不通了
另外還有再一些case下,解不是穩健的,有可能跑出虛數,但是虛數的係數其實很小…
所以就下定決心來研究一下各種WLS的解法
稍微GOOGLE了一下,發現不外乎下面四種解法:
- 直接解,就是利用
(X^T * W * X)^(-1) * X^T * W * y
去解出迴歸係數 - 再來就是把inverse部分用pseudo inverse代替,以避免rank不足的問題出現
- Cholesky Decomposition (LDL Decomposition)
- QR Decomposition
效率的話,4 > 3 > 1 > 2
,但是QR在一些情況下會跑出虛數
所以我這裡會偏向以3為主
下面是用程式去實作各種解法:
R code:
1 | Rcpp::sourceCpp("wls.cpp") |
C++ code:
1 | // [[Rcpp::depends(RcppArmadillo, RcppEigen)]] |
這裡的QR解得很慢,我不知道要怎麼樣讓armadillo只輸出跟rank一樣多的Q,R矩陣就好
而直接解會是最快的,我猜這原因是裡面某部分有被優化過了…
不然以程式來看,Cholesky Decomposition的performance是最好的
只是我也不解的是Eigen也用一樣的方法去做
卻比Armadillo手動去寫慢了好幾倍 (eigen_chol_llt vs arma_chol)
不確定是不是Eigen在solve linear system時用不一樣的LAPACK函數
或是Eigen在這做了比較多check
這裡就留給後人慢慢玩賞QQ
2017/4/20補充:
我後來試了一些簡單的case
發現其實在p不大(大概小於80),n也不大(小於200)的情況
RcppEigen擁有比較好的performance,我的猜測是SSE指令集帶來的好處
測試script如下:
1 | library(iterators) |
基於上面的結論,所以我會建議這樣去寫wls的solver:
1 | // [[Rcpp::depends(RcppArmadillo, RcppEigen)]] |