一、 简述
为了从基因的表达水平中得到更加具体直观的生物学功能变化的信息,多种基于已知的基因集的分析方法应运而生。其中,基因集分析(Gene Set Analysis)、基因集富集分析(Gene Set Enrichment Analysis)、单样本基因集富集分析(Single Sample Gene Set Enrichment Analysis, ssGSEA)、基因集变异分析(Gene Set Variation Analysis, GSVA)是我目前遇到比较多的基因集分析方法,在这里对四者做一个详细的阐述和比较,以加深对这些方法的理解。本文章不介绍代码,只阐述算法原理,因为现在这几种方法的代码的分享已经足够多了,而对于原理的详细阐述几乎没有。
二、GSA与GSEA
1. GSA
GSA属于ORA法(Over-representation Analysis) ,过表达分析。统计原理其实我们在高中就已经学了。一个袋子里有100个球,其中红球20个,白球80个,现在随机不放回地从袋子中拿出10个球,其中有n个红球的概率?在这里,总共100个球对应总共2w多个基因,红球对应基因集中的基因,从袋子中拿球的数目对应DEG的数目。
具体步骤如下:
a) 通过差异分析(limma或DESeq2等R包)基于不同的阈值设定(p-value以及log2FC)得到不同组间的差异表达基因DEG。
b) 将DEG与感兴趣的基因集做交集(KEGG、GO、MSigDB等数据库),得到一些共同的基因。
c) 基于超几何分布的Fisher检验来评估,抽到这些共同的基因的的计数值是否显著高于随机,即待测功能集在基因列表中是否显著富集。
本方法优缺点明显:摘自史上最通俗 Gene enrichment analysis 之 over representation analysis (ORA) 原理解释;
优点:基于完备的统计学理论, 结果稳健、可靠。
缺点:(1)仅使用了基因数目信息,而没有利用基因表达水平或表达差异值,为了获得感兴趣或者差异表达基因,需要人为的设置阈值;(2)ORA法通常仅使用最显著的基因,而忽略差异不显著的基因。在获得感兴趣的基因时, 往往需要选取合适的阈值, 有可能会丢失显著性较低但比较关键的基因, 导致检测灵敏性的降低;(3)将基因同等对待,ORA法假设每个基因都是独立的,忽视了基因在通路内部生物学意义的不同(如调控和被调控基因的不同)及基因间复杂的相互作用;(4)ORA假设通路与通路间是独立的,但这个前提假设是错误的。
补充几点:(1)ORA方法只关心差异表达基因而不关心其上调、下调的方向,也许同一条通路里既有显著高表达的基因,也有显著低表达的基因,因此最后得到的通路结果很难结合表型进行分析。(2)根据上下调把差异表达基因分开,并分别进行GSA,似乎可以分别得到上下调的通路。但是人为对差异基因的范围进行调整后再进行GSA是否会引入误差呢?(3)针对上下调的差异表达基因分别进行GSA,也许会同时富集到一条通路上,这怎么解释该通路的变化呢?我在分析过程中的确遇到过这样的情况。
与GSA不同,GSEA方法让通路的上下调分析成为可能:简单来说,先计算基因在不同组间表达量的log2FC,并以此从大到小进行排序,这样就得到了一个基因从上调到不变到下调的基因列表。然后,对于我们感兴趣的基因集,我们只需考察它们的成员是否富集在这个基因列表的上方(上调部分)或者下方(下调部分)即可判断这些基因集的上下调情况。
2. GSEA
GSEA在2005年被首次发表:
Subramanian A, Tamayo P, Mootha VK, et al. Gene set enrichment analysis: a knowledge-based approach for interpreting genome-wide expression profiles. Proc Natl Acad Sci U S A. 2005;102(43):15545-15550. doi:10.1073/pnas.0506580102
需要注意的是,在GSEA中,不仅仅可以用log2FC对基因进行排序,根据自己的研究内容,可以使用不同的参数比如相关性系数作为排序依据。实际上,GSEA原文是这么说的:“Genes are ranked based on the correlation between their expression and the class distinction by using any suitable metric”。在我来看目前应用得比较多的是不同组间比较得到的log2FC,因此在后面的阐述中我都将以log2FC做为排序的依据。
在讲解GSEA、ssGSEA、GSVA前,需要了解几个统计学知识,因为它们与这三个方法都息息相关。
注释1. 分布函数(Cumulative Distribution Function,CDF)与概率密度函数(probability density function,PDF)
这是比较基础的统计学概念,参考b站宋浩老师的讲解:《概率论与数理统计》教学视频全集(宋浩)p22
简单来说,对于一个随机变量X,分布函数F(x)=p{X 概率密度函数与分布函数
注释2. 经验累计分布函数(Empirical Cumulative Distribution Function,eCDF)
维基百科的解释是:
In statistics, an empirical distribution function (commonly also called an empirical Cumulative Distribution Function, eCDF) is the distribution function associated with the empirical measure of a sample.[1] This cumulative distribution function is a step function that jumps up by 1/n at each of the n data points. Its value at any specified value of the measured variable is the fraction of observations of the measured variable that are less than or equal to the specified value.简而言之,这是一个根据抽样样本数据来近似总体分布函数的方法。我们从总体中抽出n个样本{x1,x2,x3…xn},对于这个样本我们可以画一个频率密度直方图,并且我们设定每个样本的概率是1/n,于是据此可以画一个该抽样样本的分布函数。因为样本数目有限,样本变量为离散的,所以这个分布函数是阶梯函数(step function),每一步阶梯的高度都是1/n,代表每个对应的样本数据的概率为1/n,将所有的样本数据爬完后最终到达1。如果抽样样本足够多的话,eCDF也就越接近总体的CDF。
在后面GSEA、ssGSEA、GSVA的详细介绍中,对于这种阶梯式的step function,被描述为random walk,也就是随机游走,随机游走也是一个统计学概念,在这里,我们考虑一个点从原点出发向右行走,当遇到抽样分布的样本点(数据点)时(对应的横坐标),就向上走1/n,如果没遇到就平行x轴行走。在后面的GSEA、ssGSEA、GSVA中,它们的随机游走可能有着不同的策略,比如说遇到在基因集中的基因就向上走一个特定的与表达量相关的数值,没有遇到就向下走一个特定的数值。后面我们会详细讲解。
正态分布的经验分布函数
注释3 Kolmogorov–Smirnov test
这是一个非参数检验,通过比较两个抽样样本的eCDF的形状,来检验它们是否来源于同一个总体分布。往往用于检验一个抽样分布是否属于正态分布。参考10: Kolmogorov-Smirnov test
方法很简单,在同一个图上画出两个抽样样本的eCDF(样本数目分别为n、m),然后找到两条阶梯线最大的差距D,这个D就是我们需要的统计量,对于原假设H0:两抽样分布来源于同一总体,D就会很小,如果D过大(α=0.05)就可以拒绝原假设接受备择假设:两抽样分布来源于不同总体。
D本身的分布是通过非常多次改变两样本在x轴上的排序从而计算得到的,每一次打乱样本顺序,都可以计算出相应的一个D,得到一个D的分布,这样就可以考察现在的D的水平是否满足p<0.05。因为对于eCDF来说,确定样本量后,阶梯上升量就确定了,所以改变eCDF形状的因素就只剩下样本在x轴上的分布情况。在Myles Hollander等人的《Nonparametric Statistical Methods》的5.4的注释38里介绍了统计量D的显著性检验(书中用的统计量是J=(nm/(n和m的最大公约数))*D)。其中介绍了两个抽样样本X、Y且n=1、m=3时的情况。当排序为XYYY时,J=3,排序为YXYY,J=2。
https://www.youtube.com/watch?v=ZO2RmSkXK3c&ab_channel=MatthewE.Clapham
《Nonparametric Statistical Methods》的5.4的注释38
好了,现在我们可以详细具体介绍GSEA了。
GSEA的具体步骤
为了方便讲解,我们假设现在有一个包含肿瘤样本和正常样本的基因表达矩阵,包含26个基因,我们感兴趣的基因集S包含其中9个基因(行为基因,列为样本)。
第一步:计算得到与表型相关的参数。在这里,我们计算的是肿瘤样本和正常样本的每个基因表达量的log2FC值(肿瘤/正常)。
第二步:将所有基因按照log2FC从大到小排列,这样就会形成一个基因list:L,顶部的基因有较大的log2FC,表示在肿瘤中相对高表达;底部的基因有较低的log2FC(负数),表示在肿瘤中相对低表达;中间的基因则比较接近于0,表示两样本中差距不大。
第三步:计算富集分数(Enrichment Score,ES):k-s like statistic:
先看看原文的解释:
ES是k-s like statistic,所以其计算过程就与k-s检验十分相似:
上图是我随手画的。类似于k-s检验,我们已经有了一个基因list L,我们直接把它当作x轴,于是x轴变量就是所有的基因,并且是按照log2FC从大到小排列的。对于一个我们感兴趣的基因集S(包含9个基因),y轴为累计概率(cumulative probability),我们可以画出它的eCDF:红色线条。同样我们可以画出不在基因集S中的17个基因的eCDF:蓝色线条。
绿色的D(在注释二中D表示eCDF差值的最大值,从这里以开始D仅表示eCDF差值)表示两条eCDF的差值,即等于红色eCDF减去蓝色eCDF。x轴上基因list的不同基因对应了不同大小的D,因此D可以表示在该基因处两个eCDF的分布差异,因此D就是富集分数ES(在后续的介绍中,D和ES等价)。
GSEA中,我们为了强调表型的变化,也就是表型间基因表达量的log2FC,我们调整了eCDF每个阶梯的上升高度。在标准k-s的eCDF中,也就是上图所示中,阶梯上升高度是1/n(9个基因的基因集的eCDF上升高度就是1/9,同样的不在基因集S的基因的eCDF上升高度就是1/17),而在GSEA中,考虑到log2FC的权重,基因集S的eCDF的上升高度随着S内不同基因()的log2FC变化:
其中,
代表log2FC的权重,当的时候,也就是不考虑log2FC时,此时为标准k-s 的eCDF。默认。表示所有基因中属于基因集S的基因。总结下来,当时,阶梯上升高度为:
因此,在eCDF中,基因集S中的基因越是有着较大|log2FC|,其上升的阶梯就越大。
上面描述了在基因集S中的基因的上升阶梯高度,而不在基因集S中的其他基因的上升阶梯并不受log2FC的权重影响,并且与标准k-s检验的eCDF一致(阶梯高度与上图一致):
N表示所有基因的数量,NH表示感兴趣的基因集(基因集S)中包含的基因个数。所以,简单表示其上升阶梯高度即为:
D随着x轴基因list的位置不断变化,也就是下图中的红线。最终,类似于k-s test,我们用绝对值最大的D作为统计量,表示两个eCDF的分布差异,即为基因集S的富集分数ES(S)。当ES(S)为正时表示基因集S的基因富集在L的顶部,ES(S)为负时表示基因集S的基因富集在L的底部。
在原文中描述到,在随机游走过程中(也就是红线的游走路线),遇到基因集S中的基因后加上一个统计量,这个统计量就是上述的基因集S的eCDF的上升高度。没有遇到基因集S中的基因,就减去一个统计量,这个统计量也就是不在基因集S中的其他基因的eCDF上升阶梯高度。GSEA、ssGSEA、GSVA都是采用的k-s like test,也就是上述的策略,仅仅统计量的计算略有差异。在各自的原文中,D也就是ES的数学表达方式为,对整个基因list基因集S的eCDF的上升高度求和,减去不在基因集S中的其他基因的eCDF上升阶梯高度的求和。
第四步:检验ES(S)的显著性(计算ES(S)的p-value):
"Step 2: Estimation of Significance Level of ES. We estimate the statistical significance (nominal P value) of the ES by using an empirical phenotype-based permutation test procedure that preserves the complex correlation structure of the gene expression data. Specifically, we permute the phenotype labels and recompute the ES of the gene set for the permuted data, which generates a null distribution for the ES. The empirical, nominal P value of the observed ES is then calculated relative to this null distribution. Importantly, the permutation of class labels preserves gene-gene correlations and, thus, provides a more biologically reasonable assessment of significance than would be obtained by permuting genes."
采用置换检验(empirical phenotype-based permutation test),参考Permutation test(置换检验)以及在R中的应用。在这里,我们可以重新随机分配基因的log2FC(原文中的phenotype label),然后再按照上述过程计算得到新的ES(S),这样反复多次进行,次数足够大时,我们可以依据大量的新的ES(S)得到ES(S)的概率分布,然后我们在这个分布中考察之前计算的真正的ES(S)的p值(可以看出来与标准k-s test是一样的方法)。
第五步:多重假设检验:
计算完p值后,再计算FDR。原文中的FDR我认为应该是familywise error rate(FWER)。首先计算normalized ES(S),这个标准化可不是在各种基因集的ES中标准化,这里的标准化是为了消除不同基因集基因数量不同带来的影响。标准化方式如上图所述,我们在计算基因集S的 的p值的时候,通过置换检验得到了1000个不同的ES(上图中的 ),这1000个 分别可以计算出正值和负值的 平均值,然后用 除以这个平均值(对应的正负平均值),得到 ,同样的,1000个 也根据其正负除以对应的正负平均值,得到 。
然后计算q value,按照原文所述,我们把 的数值记作 ,对于 时,计算 的概率 (类似于上面计算p值的过程,只不过这里根据 的正负缩小了范围);在实验中我们感兴趣的基因集很多,每个基因集都有对应的NES,记作 ,计算 的概率 。
如果使用clusterProfiler包进行GSEA,那么结果的adjust p-value就是BH调整后的p-value,参考:通俗地解释错误发现率 (FDR)。
最后介绍一下输出结果的Leading-Edge Subset。原文如下:
输出结果的tags、list、signal概率的解释可以参考GSEA笔记。
综上我们就介绍完了GSEA。总结一下,相比起GSA,GSEA不再关注于差异基因,因此不受p-value以及log2FC阈值的影响,可以获得更多生物学功能变化的信息。富集分数ES,实际上是k-s like test的统计量,所以ES主要表示基因集S的基因的log2FC的分布与不在基因集S的其他基因的log2FC的分布是否一致,当ES大于0并且具有统计学意义时,那我们可以说基因集S内基因相比其他基因表达上调。
三、ssGSEA
ssGSEA起源于2009年的一篇文章:
Barbie DA, Tamayo P, Boehm JS, et al. Systematic RNA interference reveals that oncogenic KRAS-driven cancers require TBK1. Nature. 2009;462(7269):108-112. doi:10.1038/nature08460
接触过ssGSEA的人应该可以很直观地说出GSEA和ssGSEA的区别。GSEA是对不同表型、不同分组进行分析,不管每个分组有多少个样本,对于一个基因集S,最后只会得到一个组间或者表型间比较后的NES(S),换句话说,GSEA必须有表型或者分组信息;而ssGSEA是单样本的GSEA,对于一个基因集S,每一个样本都可以计算得到一个NES(S)。也就是说其实我们可以从表达矩阵得到一个NES矩阵,行是多个不同的基因集S,列仍然是样本。
既然是单样本的GSEA,那么主要思想应该和GSEA相差不大。先看看原文怎么描述的:
总结来说,GSEA与ssGSEA几乎一模一样,它们都需要对所有基因进行排序得到一个基因list L;都运用了k-s like test评估基因集S中的基因与S外的基因的分布是否不同,统计量的计算虽然略有不同但是思想是一模一样的。那么GSEA与ssGSEA的不同点有哪些呢?
第一, 基因的排序方法不同。在GSEA中,基因的是按照log2FC从大到小排列,而在ssGSEA中,对于单个样本,将基因按照其**绝对表达量从大到小排序。
第二, K-s like test中的eCDF阶梯上升高度所依赖的值不同。
在GSEA中,最后基因集S中基因的阶梯上升高度依赖于log2FC的加权值。而在ssGSEA中,为了消除异常值对结果的影响,在第一步排序基因后,会将表达量用秩次(rank)替换。比如说一个样本有100个基因的信息,先按照基因表达量排好序后,这个genelist对应的值是基因的表达量,然后经过秩次标准化转换后,这个genelist已经由表达量的降序排列变成了100,99,98,…,3,2,1。也就是原文L中的, , ,…,。所以最后基因集S中的基因的阶梯上升高度依赖于秩次的加权值。
并且,ssGSEA默认加权值为0.25(),
但是,不在基因集S中的其他基因的eCDF上升高度与GSEA一致的(就是GSEA中的),为:
另外,后面大家会知道,GSEA、ssGSEA、GSVA三者的不在基因集S中的其他基因的eCDF上升高度是相同的。
第三, ES(S)的计算方式不同。计算两条eCDF在每个基因处的D后,在GSEA中,ES(S)等于绝对值最大的D;而在ssGSEA中,ES(S)等于所有D的加和(积分)。
最后,对ssGSEA的计算细节感兴趣的话,可以逐行运行此代码:A simple implementation of ssGSEA (single sample gene set enrichment analysis)。
四、GSVA
GSVA和ssGSEA非常相似,同样是对单个样本进行计算,最后输出的也是一个行为不同基因集、列为样本的矩阵。首次发表于2013年:
Hänzelmann S, Castelo R, Guinney J. GSVA: gene set variation analysis for microarray and RNA-seq data. BMC Bioinformatics. 2013;14:7. Published 2013 Jan 16. doi:10.1186/1471-2105-14-7
GSVA同样也是先进行基因排序,得到一个基因list,然后通过k-s like test得到基因集内外基因分布的两条eCDF的差值D,并基于差值D得到ES(S)。基本步骤与ssGSEA一致,下面介绍GSVA与ssGSEA的不同之处:
第一:基因集的排序方法不同。竟然又有不同,这次GSVA能玩出什么花?我们看看原文:
总结一下,首先根据基因 在n个样本中的表达量,通过核密度估计(kernel estimation)得到基因 的概率密度函数,然后积分得到不同样本 的CDF值。当所有基因的所有表达值都转换成CDF值后,再在每一个样本中对基因按照CDF值从大到小排序并最终如ssGSEA一样用秩次代替CDF值。这么听着似乎有点疑惑对吧,下面再仔细点解释。
注释4:核密度估计(kernel density estimation)
可仔细参考什么是核密度估计?如何感性认识?以及Intro to Kernel Density Estimation (KDE)
对于一组数据,我们不知道其分布,我们可以通过核密度估计计算得到这一组数据的估计概率密度函数。比如我在公路的某个点记录了100辆车通过该点时的速度,我们可以基于这些数据使用核密度估计得到车辆通过该点的速度的概率密度函数,从而可以估计不同不同速度区间的车辆的数量占比。
基于这组数据可能的分布(虽然有点矛盾,但的确是这样),我们会选择不同的核函数进行核密度估计,在基因表达数据中,对于microarray数据,其log值通常符合正态分布(高斯分布),因此对于microarray数据的核密度估计选择高斯核;对于RNA-seq的counts数据,其往往服从泊松分布,因此其核密度估计选择泊松核。
回到我们的基因数据来,我们得到的是一系列样本的的表达值,现在我们简单举个例子。有14个样本的microarray表达量数据。我们可以画出其频率分布图,根据频率分布图,使用核密度函数(高斯核)估计其概率密度函数。对概率密度函数积分就可以得到对应的分布函数(CDF)值,然后用CDF值代替基因表达值。
演示代码:
genej <- c(6, 3, 2, 7, 4, 2, 7, 3, 1, 5, 3, 2, 5, 7)
hist(genej,xlim=c(-2,10),xlab = "",ylab = "",xaxt="n",yaxt="n",main = "")
gene_kernel <- density(genej)#kernel estimation
par(new=T)
plot(density(genej),xlim=c(-2,10),ylim=c(0,0.2))
p <- data.frame(approx(x=gene_kernel$x,y=gene_kernel$y,xout = genej))
plot(x=p$x,y=p$y,xlim=c(-2,10),ylim=c(0,0.2),xlab = "",ylab = "")
#get the CDF
KPDF <- approxfun(x=gene_kernel$x,y=gene_kernel$y,yleft=0, yright=0)
cdf<-sapply(Fh$x,function(probability){integrate(KPDF, -Inf,probability )})
当所有基因的表达值都转换成CDF值之后,类似于ssGSEA,在每个样本中,对所有基因按照CDF值从大到小排列,得到每个样本独特的基因排序genelist。
GSVA函数中通过kcdf(kernel estimation of cdf)选项对核函数进行选择。如上所述,microarray表达数据的log值可认为符合正态分布,所以核函数选择kcdf="Guassian"。对于RNA-seq的counts数据可以认为符合泊松分布,所以和函数选择kcdf="Poisson"。
第二:K-s like test中的eCDF阶梯上升高度所依赖的值不同:
如前面部分提到的,GSVA也采用rank normalization。类似于ssGSEA,GSVA按照CDF值在每个样本中对基因进行从大到小的排序,之后用rank值代替CDF值。ssGSEA到这里就结束了,但是GSVA新增加了一步: 中心化。将rank值围绕0进行中心化。具体操作如下:
样本 的基因 的rank值为 ,基因总数为 ,则用于计算阶梯上升高度的中心化后的rank值 为:
如此操作后可以提升基因列表头部及尾部基因的阶梯上升高度。因此,对于样本 ,基因集S内的基因其eCDF上升高度依赖于标准化后的rank值的加权值,默认权重与GSEA相同():
至于不在基因集S的其他基因eCDF上升高度就不赘述了,如前所述,与GSEA、ssGSEA一致。
第三:ES(S)的计算方式不同。
ssGSEA中的ES(S)是取所有D的积分,而GSEA则是类似于k-s test,取绝对值最大的ES作为基因集S的ES(S),GSVA提供了两种不同的ES(S)计算方法。
第一种计算方法与GSEA一致,同样的,取绝对值最大的ES作为样本在基因集S的ES(S)。第二种方法则采用一个差值:
ES(S)等于最大的D的绝对值减去最小的D的绝对值。注意这里的“最大”和“最小”不是比较D的绝对值,而是D本身,是考虑正负的,不过在做差的时候是使用二者的绝对值。这样计算是基于这样一个假设:基因集S中的基因分布在基因list的一侧(顶部或者底部)。对于在基因list两侧都有分布则会计算出很小的富集分数ES(S)。并且,方法一取绝对值最大的D作为ES(S),此时的ES(S)是双峰分布,方法二则是单峰分布,并且近似正态分布,因此对于下游分析,若对ES(S)的分布有要求,则下游分析更方便。
对于方法的选择需要斟酌,如果不确定基因集S会富集在顶部或底部,使用方法二可能不妥当。在GSVA包中,通过参数mix.diff对方法进行选择。mix.diff=T则选择方法二,mix.diff=F选择方法一。
总结
以上我们详细阐述了GSA、GSEA、ssGSEA、GSVA的算法原理,这应该是中文互联网最详细的GSEA、ssGSEA、GSVA的算法原理的阐述。可以看到除了GSA是基于超几何分布,后三者都是基于k-s test。GSEA开启了使用k-s test检验基因集富集的大门,ssGSEA提供了单样本的视角,并且引入rank normalization避免结果受基因表达的异常值的影响。GSVA相比ssGSEA,引入了核密度估计,用分布函数值代替基因表达值,并且提供了ES(S)的新的计算方法。
在实际的生信分析中,对于探究分组或表型间的生物学功能变化,推荐使用GSEA。对于不需要聚焦在分组或表型时,选择ssGSEA和GSVA的哪一种,则看工作者自己对数据的理解了。
另外,有文章深度评测不同方法的效果,感兴趣可以仔细学习:Yasir Rahmatallah, Frank Emmert-Streib, Galina Glazko, Gene set analysis approaches for RNA-seq data: performance evaluation and application guideline, Briefings in Bioinformatics, Volume 17, Issue 3, May 2016, Pages 393–407, https://doi.org/10.1093/bib/bbv069
最后,感谢本文所引用内容的作者,他们来自不同的中文网络社区:、CSDN、知乎、哔哩哔哩,除此之外还有海外的油管。感谢这些作者对自己知识的无私分享。