Home | About | Posts | English

Principal component analysis (PCA) 的R實作

2021/09/04
這篇建議搭配主成分分析一起服用。
用R跑PCA相當的容易,容易到很多人不懂PCA卻也弄得出來,但建議還是要先理解PCA的原理才開始使用,R筆記也是一個很棒的參考點。

用R寫PCA

首先我使用在主成分分析文章中使用的學生資料做示範,表格如下:

Student Math Science English
Andy 98 97 52
Bob 48 58 90
Caleb 44 65 99
David 92 96 63
Ethan 42 57 86
Frank 70 80 70

將數據輸入R

dat <- data.frame(matrix(c(98,97,52,48,58,90,44,65,99,92,96,63,42,57,86,70,80,70), nrow=6, ncol=3, byrow = T))   
row.names(dat) <- c("Andy","Bob","Caleb","David","Ethan","Frank")    
colnames(dat) <- c("Math", "Science", "English")   

接著要使用的函數名為prcomp,即是principal component的意思,他所需要的參數有三個,分別為formuladatascale
formula代表要使用哪些變數資料做主成分分析,使用三個科目表示
formula = ~ Math+Science+Englishdata則是資料的名字,scale是True or False,輸入T代表數據會經過標準化 (減去平均再除以標準差),強烈建議需要標準化資料,因為有些變數的範圍差距很大,會影響結果。

pca <- prcomp(formula = ~ Math+Science+English,  
              data = dat,                          
              scale = T)  
pca

若變數很多不想一個一個打字的話,提供可以使用paste(colnames(dat),collapse = "+")這行指令。

至此,我們的主成分分析已經完成 (這麼快!?)
所有需要的數據都存在pca這個資料裡,應該會顯示下面這樣

Standard deviations (1, .., p=3):
[1] 1.70179452 0.30930959 0.09068076

Rotation (n x k) = (3 x 3):
               PC1       PC2        PC3
Math    -0.5854414 0.1504653  0.7966295
Science -0.5762037 0.6140123 -0.5394240
English  0.5703049 0.7748220  0.2727695

所謂的rotation就是變數的負荷量 (loading),依照我的習慣,我會先看主成分分析的eigenvalue與累積解釋變異。

vars <- (pca$sdev)^2                # 提取特徵值
props <- vars / sum(vars)           # 提取解釋比例
cumulative.props <- cumsum(props)   # 提取累積比例
vars                                # 呼叫特徵值
cumulative.props                    # 呼叫累積比例

提取出來的vars就是eigenvalue,cumulative.props就是累積的解釋變異,輸出的結果應該如下:

> vars
[1] 2.89610458 0.09567243 0.00822300
> cumulative.props 
[1] 0.9653682 0.9972590 1.0000000

我們可以看到PC1的eigenvalue有2.896,但PC2的eigenvalue只有0.096,根據Kaiser’s rule (凱莎原則),eigenvalue > 1的主成分較好,而在累積解釋比例的部分,PC1就能解釋97%的變異,可以說是相當好 (因為數字是我調過的,現實哪有這麼好的事情)。
確定PC1的效果很好之後,下一步要做的就是取出各變數的loading,這步驟使用pca$rotation,從pca資料抽取出rotation (也就是loading)。

> pca$rotation
               PC1       PC2        PC3
Math    -0.5854414 0.1504653  0.7966295
Science -0.5762037 0.6140123 -0.5394240
English  0.5703049 0.7748220  0.2727695

結果如上,PC1中數學與科學的loading都是負的,而英文則是正的,這跟我們在主成分分析文章中發現的一樣,有隱藏的變數 (理組傾向),當理組傾向越高時數學跟自然的成績越好,英文成績越差,而PC1就將這個傾向表現出來。另外,loading的正負號僅表示不同變數之間的相對性,其絕對值越大才是代表影響越大。

PCA的結果呈現上,第一個會表示其累積百分比,再來是變數loading,最後一個則是score plot,這三個都呈現出來,你的PCA才完整,現在要來繪製score plot。
由於繪圖多只能繪製二維圖,所以通常會挑選前兩個主成分 (PC1及PC2) 來繪圖,但如果其他的很有趣當然也可以畫。要將score提取出來,使用pca$x來提取各樣本 (學生) 數據在投影到PC1後的score。

> pca$x
             PC1        PC2         PC3
Andy  -2.2254737 -0.1477052  0.02261740
Bob    1.3932171 -0.1193047  0.15567019
Caleb  1.5526425  0.4817224 -0.04236503
David -1.7024518  0.2583078  0.02778427
Ethan  1.4385213 -0.3623239 -0.06764923
Frank -0.4564554 -0.1106965 -0.09605761

將前面兩個PC繪圖表示,推薦使用套件函數autoplot可以快速畫出能看的圖 (當然要美觀還是要細調,但這已經能看了),需要下載套件ggplot2與ggfortify。

library(ggplot2)
library(ggfortify)
autoplot(pca, data = dat,     
         size=2,                 
         x=1, y=2,
         scale=F)+
geom_text(vjust=-1, label=rownames(dat), cex=4)

接著應該就會看見下面這張圖

在PC1上面,落在右邊的三個人 (Bob、Caleb和Ethan) 是屬於理科傾向較低,英文考較好的學生,反之另一邊的兩個人 (Andy及David) 則是理科傾向較高,數學與科學考較好的學生,PCA就能如此揭露隱藏在數據後面的另一個維度

最後的叮嚀

雖然PCA很強大,但仍有一些需要注意的地方。

其他能夠參考繪圖的網站:
https://cran.r-project.org/web/packages/ggfortify/vignettes/plot_pca.html
https://stackoverflow.com/questions/40223219/autoplot-how-to-adjust-loading-labels

更新:我又寫了另一篇PCA的R教學歡迎去看。