在进行统计学分析中往往面临着比较难以抉择的权衡。以农学研究为例,在实验设计时,考虑到研究结论更能反应作物真实状态下的农艺性状,研究人员会尽可能的纳入较多的指标,但是,随着而来的是铺天盖地的数据让人难以下手,主成分分析(principal component analysis,PCA)便很好的解决了这一问题。
在生物学相关(因为我主要从事生物学研究 ^ _^)领域,PCA应用范围极广。光我接触过的便有数种:群体遗传学遗传成分的划分、代谢组学关键化合物的分离、群落学不同群落差异的评估、环境DNA组分的划分……
1 PCA
原理
假设我们分别调查了几个群落的物种丰富度和各物种的多度,正如上述所言,就算只对三个群落进行调查,每个群落三个生物学重复,但是哪怕是群落构成单一如农田生态系统也有近百种物种构成,这时我们拿到的数据就是一个 9 × 100 9\times100 9×100的数据矩阵。
为了方便理解,假设我调查了 i i i个群落,其中物种最多的群落有 j j j个物种,这时我们就得到了下面的一个数据矩阵 A i × j A_{i\times j} Ai×j:
A i × j = [ x 11 x 12 … … x 1 j x 21 x 22 … … x 2 j . . … … . x i 1 x i 2 … … x i j ] A_{i\times j}= \begin{bmatrix} x_{11} & x_{12}& …… & x_{1j}\\ x_{21} & x_{22}& …… & x_{2j}\\ . & . & …… & . \\ x_{i1} & x_{i2} & …… & x_{ij} \\ \end{bmatrix} Ai×j= x11x21.xi1x12x22.xi2……………………x1jx2j.xij
而每个物种即构成了一个这个矩阵的列向量 x → j \overrightarrow x_j xj:
( x → 1 , x → 2 , … … , x → j ) (\overrightarrow x_1,\overrightarrow x_2,……,\overrightarrow x_j) (x1,x2,……,xj)
避开晦涩的数学推导过程,通俗的以几何图形的方式理解。在这个物种构成矩阵,可形成一个 j j j维的空间,每个物种的列向量 x → j \overrightarrow x_j xj为其所在维度的坐标系:
每个样本构成的行向量:
( x → 1 , x → 2 , … … , x → i ) (\overrightarrow x_1,\overrightarrow x_2,……,\overrightarrow x_i) (x1,x2,……,xi)
可看作是在此 j j j维空间内的 i i i个点,其对应的物种构成即为 j j j维坐标:
通过对每个向量构成元素的离散度(方差 S 2 S^2 S2)进行比较,离散度最大的向量对组间变异(即群落构成差异)的解释率最高,那么这个向量 x → n \overrightarrow x_n xn即为主成分1(PC1):
为避免各解释向量间的交互效应,过PC1轴取其正交平面 α \alpha α。在 α \alpha α平面内再次取离散度最大的向量轴 x → m \overrightarrow x_m xm作为主成分2(PC2):
最后将结果在二维的平面展示就是我们经常看到的PCA可视化结果:
通过此方法即可快速找出数据矩阵中对组间变异解释度(贡献率)最高的几个指标,在此例子中就是对各群落结构差异贡献最大的几个物种。同理,将此思路推广到其他几个应用领域即为:对农产品品质差异影响最大的农艺性状;对代谢组差异贡献最大的代谢物……
2 实战
vegan
包是生态学分析中较为常用的包,特别是各种排序图绘制功能(包括PCA),但缺点是绘制的图可能不及ggplot系列(没错,ggplot也有针对PCA的功能)美观。
2.1 vegan
包
此时使用的数据是一个模拟的宏基因组数据,三个样点,每个样点20个重复,总计60个样本。
首先加载包、读取数据:
#加载包,前两个为依赖包
library(permute)
library(lattice)
library(vegan)#1.
#设置工作环境,读取数据
getwd()
setwd("D:/dir/CSDN/PCA/")#读取数据
data<-read.csv("example.csv",header=T)head(data)
#site otu_1 otu_2 otu_3 otu_4 otu_5 otu_6 otu_7 otu_8 otu_9 otu_10 otu_11 otu_12 otu_13 otu_14 otu_15 otu_16 otu_17 otu_18 otu_19 otu_20 otu_21 otu_22#site_1 1 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 2 0 0 0 0 1#site_1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 2 0 0 0 0#site_1 0 6 0 0 0 0 0 1 0 0 0 0 0 0 0 0 1 0 0 0 0 0#site_1 1 0 6 1 6 1 5 0 0 1 1 0 1 0 0 1 1 0 0 0 0 0#site_1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 4 0 0 0 0 0#site_1 2 5 0 55 7 0 0 0 0 0 0 0 2 0 0 0 6 0 0 2 0 4
根据数据维度对数据进行切片降维:
#2.
#数据分析#查看数据维度,因为降维过程不需要样点信息列
dim(data)
#输出为:
#[1] 60 94#根据前一步输出提取数据的主要部分,并降维
data_pca<-rda(data[,2:94])#查看主要结果
summary(data_pca)
由于是模拟数据的缘故,解释率可能会比较奇怪:
最后就是可视化:
# 生成坐标系
# 注意根据pca结果更改坐标轴名称
fig<-ordiplot(data_pca,type="none",xlab="PC1(13.12%)",ylab="PC2(11.70%)")# 将各样本点映射到坐标系
points(fig,"sites",pch=16,col="#FF4900FF",cex=1,select=data$site=="site_1")
points(fig,"sites",pch=16,col="#FF80FFFF",cex=1,select=data$site=="site_2")
points(fig,"sites",pch=16,col="#2A7AB7",cex=1,select=data$site=="site_3")
显示各OTUs信息:
# 显示各指标(列向量)
text(fig, "species", col="grey", cex=1)
# 也可以显示列向量为点
points(fig, pch=16,"species", col="grey", cex=1)
添加图例以及置信椭圆:
# 添加图例
legend(0,10, c("Site 1","Site 2", "Site 3"), text.col = c("black","black","black"),pch = c(16,16,16),col=c("#FF4900FF","#FF80FFFF","#2A7AB7"),cex=1,merge = F,bty = "n")# 读取分组信息
env<-read.csv("site.csv",header=T)# 添加置信椭圆
with(env,ordiellipse(data_pca,site,kind="se",col=c("#FF4900FF","#FF80FFFF","#2A7AB7"),conf = 0.99))
2 ggplot2
此次使用的数据是来自于三种生境的授粉昆虫多样性调查,每种生境分别做了12次重复。数据分析涉及的包为:ggplot2
、factoextra
、FactoMineR
。相关的分析方法和原理与vegan类似:
library(ggplot2)
library(factoextra)
library(FactoMineR)# 1.
# 读取数据
setwd("D:/dir/CSDN/PCA/")
data<- read.csv("example2.csv")# 2.
# 降维,注意这提供了另一种切片方法
data_pca<- PCA(data[,-1], graph = FALSE)
summary(data_pca)# 3.
# 可视化
fviz_pca_ind(data_pca,geom.ind = "point", pointsize =3,pointshape = 21,fill.ind = data$site, addEllipses = TRUE, legend.title = "Groups",title="")+theme_grey() +theme(text=element_text(size=12,face="plain",color="black"),axis.title=element_text(size=11,face="plain",color="black"),axis.text = element_text(size=10,face="plain",color="black"),legend.title = element_text(size=11,face="plain",color="black"),legend.text = element_text(size=11,face="plain",color="black"),legend.background = element_blank(),legend.position="right")
#出图
#脚本参考自EasyCharts团队
最后,ggplot2
做为强大的可视化工具,也可接受vegan包结果的投影,并使用ggplot的可视化思路进行绘图(之前做过,存脚本的磁盘坏了……)。