一文看懂PCA主成分分析中介紹了PCA分析的原理和分析的意義(基本簡介如下,更多見博客),今天就用數據來實際操練一下。
在生信寶典公眾號后臺回復“PCA實戰”,獲取測試數據。
一、PCA應用
# 加載需要用到的R包library(psych)
library(reshape2)
library(ggplot2)
library(factoextra)
1. 數據初始化
# 基因表達數據
exprData <- "ehbio_salmon.DESeq2.normalized.symbol.txt"
# 非必須
sampleFile <- "sampleFile"
2. 數據讀入
# 為了保證文章的使用,文末附有數據的新下載鏈接,以防原鏈接失效
data <- read.table(exprData, header=T, row.names=NULL,sep="\t")
# 處理重復名字,謹慎處理,先找到名字重復的原因再決定是否需要按一下方式都保留
rownames_data <- make.names(data[,1],unique=T)
data <- data[,-1,drop=F]
rownames(data) <- rownames_data
data <- data[rowSums(data)>0,]
# 去掉方差為0 的行,這些本身沒有意義,也妨礙后續運算
data <- data[apply(data, 1, var)!=0,]
3. 數據預處理(可選)
# 計算中值絕對偏差 (MAD, median absolute deviation)度量基因表達變化幅度
# 在基因表達中,盡管某些基因很小的變化會導致重要的生物學意義,
# 但是很小的觀察值會引入很大的背景噪音,因此也意義不大。
# 可以選擇根據mad值過濾,取top 50, 500等做分析
mads <- apply(data, 1, mad)data <- data[rev(order(mads)),]
# 此處未選
# data <- data[1:500,]
dim(data)
4. PCA分析
# Pay attention to the format of PCA input
# Rows are samples and columns are variables
data_t <- t(data)
variableL <- ncol(data_t)
if(sampleFile != "") {
sample <- read.table(sampleFile,header = T, row.names=1,sep="\t")
data_t_m <- merge(data_t, sample, by=0)
rownames(data_t_m) <- data_t_m$Row.names
data_t <- data_t_m[,-1]
}
# By default, prcomp will centralized the data using mean.
# Normalize data for PCA by dividing each data by column standard deviation.# Often, we would normalize data.
# Only when we care about the real number changes other than the trends,
# `scale` can be set to TRUE.
# We will show the differences of scaling and un-scaling effects.
pca <- prcomp(data_t[,1:variableL], scale=T)
# sdev: standard deviation of the principle components.
# Square to get variance
# percentVar <- pca$sdev^2 / sum( pca$sdev^2)
# To check what's in pca
print(str(pca))
5. PCA結果展示
# PCA結果提取和可視化神器
# http://www.sthda.com/english/articles/31-principal-component-methods-in-r-practical-guide/112-pca-principal-component-analysis-essentials/
library(factoextra)
1. 碎石圖展示每個主成分的貢獻
# 如果需要保持,去掉下面第1,3行的注釋
#pdf("1.pdf")
fviz_eig(pca, addlabels = TRUE)
#dev.off()
2. PCA樣品聚類信息展示
# repel=T,自動調整文本位置
fviz_pca_ind(pca, repel=T)
3. 根據樣品分組上色
# 根據分組上色并繪制
fviz_pca_ind(pca, col.ind=data_t$conditions, mean.point=F, addEllipses = T, legend.title="Groups")
4. 增加不同屬性的橢圓
“convex”: plot convex hull of a set o points.
“confidence”: plot confidence ellipses around group mean points as the function coord.ellipse() [in FactoMineR].
“t”: assumes a multivariate t-distribution.
“norm”: assumes a multivariate normal distribution.
“euclid”: draws a circle with the radius equal to level, representing the euclidean distance from the center. This ellipse probably won’t appear circular unless coord_fixed() is applied.
# 根據分組上色并繪制95%置信區間
fviz_pca_ind(pca, col.ind=data_t$conditions, mean.point=F, addEllipses = T, legend.title="Groups", ellipse.type="confidence", ellipse.level=0.95)
5. 展示貢獻最大的變量 (基因)
1) 展示與主坐標軸的相關性大于0.99的變量 (具體數字自己調整)
# Visualize variable with cos2 >= 0.99
fviz_pca_var(pca, select.var = list(cos2 = 0.99), repel=T, col.var = "cos2", geom.var = c("arrow", "text") )
2)展示與主坐標軸最相關的10個變量
# Top 10 active variables with the highest cos2
fviz_pca_var(pca, select.var= list(cos2 = 10), repel=T, col.var = "contrib")
3)展示自己關心的變量(基因)與主坐標軸的相關性分布
# Select by names
# 這里選擇的是MAD值最大的幾個基因
name <- list(name = c("FN1", "DCN", "CEMIP","CCDC80","IGFBP5","COL1A1","GREM1"))
fviz_pca_var(pca, select.var = name)
6. biPLot同時展示樣本分組和關鍵基因
# top 5 contributing individuals and variable
fviz_pca_biplot(pca,
fill.ind=data_t$conditions,
palette="joo",
addEllipses = T,
ellipse.type="confidence",
ellipse.level=0.95,
mean.point=F,
col.var="contrib",
gradient.cols = "RdYlBu",
select.var = list(contrib = 10),
ggtheme = theme_minimal())
二、PCA分析注意事項
一般說來,在PCA之前原始數據需要中心化(centering,數值減去平均值)。中心化的方法很多,除了平均值中心化(mean-centering)外,還包括其它更穩健的方法,比如中位數中心化等。
除了中心化以外,定標 (Scale, 數值除以標準差) 也是數據前處理中需要考慮的一點。如果數據沒有定標,則原始數據中方差大的變量對主成分的貢獻會很大。數據的方差與其量級成指數關系,比如一組數據
(1,2,3,4)
的方差是1.67
,而(10,20,30,40)
的方差就是167
,數據變大10倍,方差放大了100倍。但是定標(scale)可能會有一些負面效果,因為定標后變量之間的權重就是變得相同。如果我們的變量中有噪音的話,我們就在無形中把噪音和信息的權重變得相同,但PCA本身無法區分信號和噪音。在這樣的情形下,我們就不必做定標。
一般而言,對于度量單位不同的指標或是取值范圍彼此差異非常大的指標不直接由其協方差矩陣出發進行主成分分析,而應該考慮對數據的標準化。比如度量單位不同,有萬人、萬噸、萬元、億元,而數據間的差異性也非常大,小則幾十大則幾萬,因此在用協方差矩陣求解主成分時存在協方差矩陣中數據的差異性很大。在后面提取主成分時發現,只提取了一個主成分,而此時并不能將所有的變量都解釋到,這就沒有真正起到降維的作用。此時就需要對數據進行定標(scale),這樣提取的主成分可以覆蓋更多的變量,這就實現主成分分析的最終目的。但是對原始數據進行標準化后更傾向于使得各個指標的作用在主成分分析構成中相等。對于數據取值范圍不大或是度量單位相同的指標進行標準化處理后,其主成分分析的結果與仍由協方差矩陣出發求得的結果有較大區別。這是因為對數據標準化的過程實際上就是抹殺原有變量離散程度差異的過程,標準化后方差均為1,而實際上方差是對數據信息的重要概括形式,也就是說,對原始數據進行標準化后抹殺了一部分重要信息,因此才使得標準化后各變量在主成分構成中的作用趨于相等。因此,對同度量或是取值范圍在同量級的數據還是直接使用非定標數據求解主成分為宜。
中心化和定標都會受數據中離群值(outliers)或者數據不均勻(比如數據被分為若干個小組)的影響,應該用更穩健的中心化和定標方法。
PCA也存在一些限制,例如它可以很好的解除線性相關,但是對于高階相關性就沒有辦法了,對于存在高階相關性的數據,可以考慮Kernel PCA,通過Kernel函數將非線性相關轉為線性相關,關于這點就不展開討論了。另外,PCA假設數據各主特征是分布在正交方向上,如果在非正交方向上存在幾個方差較大的方向,PCA的效果就大打折扣了。
參考資料
http://stackoverflow.com/questions/22092220/plot-only-y-axis-but-nothing-else
http://www.sthda.com/english/wiki/scatterplot3d-3d-graphics-r-software-and-data-visualization
http://gastonsanchez.com/how-to/2014/01/15/Center-data-in-R/
http://www.statpower.net/Content/310/R Stuff/SampleMarkdown.html
http://www2.edu-edu.com.cn/lesson_crs78/self/02198/resource/contents/ch_05/ch_05.html
http://stackoverflow.com/questions/1249548/side-by-side-plots-with-ggplot2