【WGCNA学习笔记】无尺度分布和软阈值

【WGCNA学习笔记】无尺度分布和软阈值

使用WGCNA进行分析时,一定会遇到这两幅图,其中有这么几个重要的概念,软阈值,无尺度网络分布。

使用WGCNA分析时,这两幅图肯定会使用到,这两幅图的主要价值就在于寻找软阈值,构建无尺度分布网络。

image.png

无尺度分布

网络中的节点服从幂律分布,叫做无尺度网络分布。为什么是这样呢?

二八法则 就是一种幂律分布,80%的人占据着不到20%的财富,而极少数的人占据着大量的财富。一些少数关键的节点和其他节点有着丰富的联系,而大部分的节点与其他节点联系少,这些关键节点就叫作hub 节点,枢纽节点。

下面这个图,形象的表现了这个关系。钟形曲线是正态分布,幂律分布就是少数节点有极端的节点连接数。

随机网络是可以用一个值来衡量大多数节点之间的距离,或者是6或者是60,也就是你可以用一个尺度去衡量他,可以称为尺度网络。

而有巨人的网络,没办法来衡量两个节点之间的距离,叫作无尺度分布,该分布又叫做幂律分布,我们说的二八定律,长尾定律都是幂律分布的口头化呈现。

生物学相关的连接是符合这种无尺度网络分布的,也就是幂律分布,这样分布的好处在于少了其中的一些节点,这个网络依然能够正常的运转。

真实的生物学网络比如:

human disease network,

gene co-expression networks,

protein-protein interaction networks,

cell-cell interaction networks,

the world wide web and social interaction networks

生物体内,对于一个细胞而言,其中表达了很多蛋白或者RNA,但是不是每一个的作用都一样,其中有一些起到了极端重要的作用,而有一些作用甚微。对于一个微环境中,有一些细胞可能对于微环境的功能起到很重要的作用,某一些作用一般。

这种生物学网络就符合无尺度网络分布

WGCNA就是利用了这样的规律,让基因之间的联系符合无尺度分布。

软阈值

WGCNA全称是Weighted Gene Co-Expression Network Analysis,加权基因共表达网络分析。网络中基因与基因是否连接,取决于是否发生共表达。

真实网络中,计算共表达的方法有很多种,WGCNA官网给出的方法是Pearson相关性分析,我们通过计算得到两个基因的相关性系数后,如何确定两个基因在网络中连边呢。

这个时候,有两种思路,直接按照差异分析的方法,确定一个相关性系数,比如0.7,大于这个相关性系数的,我们就认为共表达,小于这个的,我们就认为这是非共表达。这个时候选用0.7作为分界点一刀切,就是"hard threshold",即就是不加权。

这种方法的有点就在于,简单直接。

但缺点也很明显:

怎样确定这个阈值,把0.7作为分界点,那0.69的相关性怎么办?

真实的生物学网络,这种非黑即白的定义方法不符合实际。就如同上面所说,大多数生物学网络符合说明无尺度网络分布。

因此,这个时候就引入了软阈值这个概念。

那么怎么确定这个软阈值。

计算软阈值

WGCNA有直接计算软阈值的函数,可以把函数拆解开,自己学习一下。

载入数据

载入WGCNA官方的数据,行是样本名称,列是基因名称

WGCNA首先使用相关性分析,上文中提到Pearson相关性算法,计算任意两个基因之间的相关性。为了避免上文中提到直接使用hard threshold的缺陷,WGCNA给相关性加了一个幂次。

图片来自WGCNA的分析中为什么要挑选软阈值

图中的绿线原来的相关性,进行幂次计算之后(8次)就变成了红色。

可以看到整体的相关性都变小了,但是里面本来就小的变得更加小。

我其实对这个图还是没有特别的理解,相关性是横坐标,纵坐标是邻接性,和得出的结论似乎不太符合。留作以后的思考吧。

为什么要给相关性加上幂次运算呢,这样就使得更符合幂律分布,符合无尺度网络的特点了。

先计算基因两两之间的相关性

cor_data <- cor(datExpr,use = 'p', method = 'pearson')

cor_data[1:5,1:5]

这是采用R自带的函数进行计算,得到的结果是

> cor_data[1:5,1:5]

MMT00000044 MMT00000046 MMT00000051 MMT00000076 MMT00000080

MMT00000044 1.00000000 -0.03797242 0.09326526 0.24716099 0.13636580

MMT00000046 -0.03797242 1.00000000 -0.56393957 -0.02934881 -0.06291723

MMT00000051 0.09326526 -0.56393957 1.00000000 0.06120014 -0.05422173

MMT00000076 0.24716099 -0.02934881 0.06120014 1.00000000 -0.02327867

MMT00000080 0.13636580 -0.06291723 -0.05422173 -0.02327867 1.00000000

然后使用WGCNA包的相关性算法计算

cor_data_WGCNA <- WGCNA::cor(datExpr,use = 'p')

cor_data_WGCNA[1:5,1:5]

结果是这样

> cor_data_WGCNA[1:5,1:5]

MMT00000044 MMT00000046 MMT00000051 MMT00000076 MMT00000080

MMT00000044 1.00000000 -0.03797242 0.09326526 0.24716099 0.13636580

MMT00000046 -0.03797242 1.00000000 -0.56393957 -0.02934881 -0.06291723

MMT00000051 0.09326526 -0.56393957 1.00000000 0.06120014 -0.05422173

MMT00000076 0.24716099 -0.02934881 0.06120014 1.00000000 -0.02327867

MMT00000080 0.13636580 -0.06291723 -0.05422173 -0.02327867 1.00000000

两种计算的结果是一样的,也就说明WGCNA的算法采用的是Pearson相关性算法。

我在这里试验了一下使用spearman算法,耗时比较长。应该是spearman算法计算相关性时,每次计算需要将每组的顺序进行排列,这个时候就会很耗费算力。

给相关性加一个幂次

为什么要加一个幂次,作者就是通过加上幂次的方式,强行让基因之间的连通性开始符合幂律了。

果子试验的时候是以10次幂进行,我选择8次幂看看效果。

power <- 8

ADJ=abs(cor(datExpr,use = 'p'))^power

这样,将相关性矩阵绝对值之后,都给了一个8次幂,结果如下

> dim(ADJ)

[1] 3600 3600

> ADJ[1:5,1:5]

MMT00000044 MMT00000046 MMT00000051 MMT00000076 MMT00000080

MMT00000044 1.000000e+00 4.322615e-12 5.724787e-09 1.392642e-05 1.195759e-07

MMT00000046 4.322615e-12 1.000000e+00 1.022965e-02 5.504572e-13 2.455594e-10

MMT00000051 5.724787e-09 1.022965e-02 1.000000e+00 1.967975e-10 7.471142e-11

MMT00000076 1.392642e-05 5.504572e-13 1.967975e-10 1.000000e+00 8.623133e-14

MMT00000080 1.195759e-07 2.455594e-10 7.471142e-11 8.623133e-14 1.000000e+00

然后对每一列的基因进行求和,得到的就是这个基因跟其他基因相关性之和。减去1是排除了自身。

k=apply(ADJ,2,sum) -1

hist(k)

结果如下

> k[1:10]

MMT00000044 MMT00000046 MMT00000051 MMT00000076 MMT00000080 MMT00000102 MMT00000149

0.0814313 15.6397241 10.3721409 0.5134981 11.9155349 3.1397842 16.5059843

MMT00000159 MMT00000207 MMT00000212

15.6716271 22.4635281 1.0466731

横坐标是基因的连接度,纵坐标是拥有该连接点数的频率,大体看上去,是头大尾巴长的幂律分布。

但是,符合与否,还要有相应的检验才可以,具体如何确定一个数据是否符合幂律分布,可看本片文章

这里大致说明,把连通性分隔,分隔内连通性的平均值取log10,跟频率的概率取log10,两者之间有线性关系。为什么是这样,这副图做了一个说明

图片来自无标度网络幂律分布

那么大致画图看一下

先把k从小到大排序,切割成20份

cut1=cut(k,20)

计算每个区间的平均值

binned.k=tapply(k,cut1,mean)

binned.k

> binned.k

(-0.0728,3.82] (3.82,7.63] (7.63,11.5] (11.5,15.3] (15.3,19.1]

2.094294 5.583894 9.466252 13.116735 17.016110

(19.1,22.9] (22.9,26.7] (26.7,30.5] (30.5,34.3] (34.3,38.2]

20.917832 24.597606 28.535248 31.739992 36.147825

(38.2,42] (42,45.8] (45.8,49.6] (49.6,53.4] (53.4,57.2]

40.351527 43.414818 48.002510 51.974849 55.419944

(57.2,61.1] (61.1,64.9] (64.9,68.7] (68.7,72.5] (72.5,76.4]

59.009976 62.642794 66.517636 70.593310 74.597006

然后计算每个区间的频率

freq1=tapply(k,cut1,length)/length(k)

freq1

> freq1

(-0.0728,3.82] (3.82,7.63] (7.63,11.5] (11.5,15.3] (15.3,19.1]

0.392222222 0.224722222 0.137222222 0.083333333 0.051388889

(19.1,22.9] (22.9,26.7] (26.7,30.5] (30.5,34.3] (34.3,38.2]

0.032777778 0.016944444 0.016111111 0.008611111 0.005277778

(38.2,42] (42,45.8] (45.8,49.6] (49.6,53.4] (53.4,57.2]

0.001111111 0.003055556 0.002222222 0.002777778 0.001388889

(57.2,61.1] (61.1,64.9] (64.9,68.7] (68.7,72.5] (72.5,76.4]

0.005555556 0.003611111 0.003888889 0.004722222 0.003055556

画图查看

# 查看均值的对数和频率的对数是否为线性

plot(log10(binned.k),log10(freq1+.000000001),xlab="log10(k)",ylab="log10(p(k))")

将分割范围确定为20的情况

将分割范围确定为10的情况

将分割范围确定为30的情况

无限的分割,就越接近于单个个体

从上面的图中可以大致看出,呈现一个线性的趋势,那么通用线性函数加线和注释,如下所示(也就是检验是否符合线性关系)。

这个时候就是将问题转化为了查看 和 是否符合线性关系。

plot(log10(binned.k),log10(freq1+.000000001),xlab="log10(k)",ylab="log10(p(k))")

xx= as.vector(log10(binned.k))

lm1=lm(as.numeric(log10(freq1+.000000001))~ xx )

lines(xx,predict(lm1),col=2, lty = 1, lwd = 3)

title(paste( "scale free R^2=",as.character(round(summary(lm1)$adj.r.squared,2)), " slope=", round(lm1$coefficients[[2]],2)))

提取这个检验中的内容

> summary(lm1)

Call:

lm(formula = as.numeric(log10(freq1 + 1e-09)) ~ xx)

Residuals:

Min 1Q Median 3Q Max

-0.8811 -0.1809 0.1189 0.2193 0.3454

Coefficients:

Estimate Std. Error t value Pr(>|t|)

(Intercept) 0.2989 0.2228 1.341 0.191

xx -1.6776 0.1477 -11.360 5.36e-12 ***

---

Signif. codes: 0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

Residual standard error: 0.3266 on 28 degrees of freedom

Multiple R-squared: 0.8217, Adjusted R-squared: 0.8154

F-statistic: 129.1 on 1 and 28 DF, p-value: 5.362e-12

这里我们提取的是调整后的R^2

探究不同的次幂的影响

上面是对采用8次幂的结果的观察,那么如果采用其他次幂是什么样子

构建一个计算函数

mypick <- function(powerVector,datExpr){

power <- powerVector

cor<-stats::cor

ADJ=abs(cor(datExpr,use = 'p'))^power

k=apply(ADJ,2,sum) -1

cut1=cut(k,10)

binned.k=tapply(k,cut1,mean)

freq1=tapply(k,cut1,length)/length(k)

xx= as.vector(log10(binned.k))

lm1=lm(as.numeric(log10(freq1+.000000001))~ xx )

return(data.frame(Power=power,

SFT.R.sq=as.character(round(summary(lm1)$r.squared,2)),

slope=round(lm1$coefficients[[2]],2),

mean.k=mean(k)))

}

仔细看上面的函数代码,其实是把上面单个的步骤,集合到了一起,写好函数,可以用循环思维,求取其他值。上面的代码,将R^2的从Adjusted R-squared更换为 R-squared,因为WGCNA使用的是 R-squared,而不是Adjusted R-squared。

具体函数结果要返回什么值,主要取决于自己的画图需求

测试一下函数可用否

mypick(6,datExpr)

结果

> mypick(6,datExpr)

Power SFT.R.sq slope mean.k

1 6 0.89 -1.5 19.90579

然后批量计算出其他阈值的情况

powers = c(c(1:10), seq(from = 12, to=20, by=2))

do.call(rbind,lapply(powers,mypick,datExpr))

结果如下

> do.call(rbind,lapply(powers,mypick,datExpr))

Power SFT.R.sq slope mean.k

1 1 -0.09 0.34 746.977852

2 2 0.02 -0.60 254.497776

3 3 0.26 -1.03 111.004761

4 4 0.44 -1.42 56.535969

5 5 0.64 -1.72 32.154311

6 6 0.89 -1.50 19.905790

7 7 0.91 -1.67 13.192338

8 8 0.89 -1.72 9.248524

9 9 0.84 -1.70 6.795315

10 10 0.81 -1.66 5.193521

11 12 0.84 -1.48 3.332680

12 14 0.86 -1.38 2.348905

13 16 0.9 -1.30 1.767929

14 18 0.9 -1.24 1.393515

15 20 0.92 -1.21 1.135087

结合这个表格,一般会选取6,作为power值,因为从5到6,R^2显著提升。也就是所说的软阈值

代码是从公众号摘录的,其中使用到的批量思维do.call + lapply + function,确实值得细细品味,并加以应用。循环的思维在分析中,能够提高效率。

WGCNA官方版本

powers = c(c(1:10), seq(from = 12, to=20, by=2))

sft = pickSoftThreshold(datExpr, powerVector = powers)

根据果子学生信所说,WGCNA采用了分块化和并行方法,所以速度会快很多。

结果如下:

> powers = c(c(1:10), seq(from = 12, to=20, by=2))

> sft = WGCNA::pickSoftThreshold(datExpr, powerVector = powers)

Power SFT.R.sq slope truncated.R.sq mean.k. median.k. max.k.

1 1 0.0278 0.345 0.456 747.00 762.0000 1210.0

2 2 0.1260 -0.597 0.843 254.00 251.0000 574.0

3 3 0.3400 -1.030 0.972 111.00 102.0000 324.0

4 4 0.5060 -1.420 0.973 56.50 47.2000 202.0

5 5 0.6810 -1.720 0.940 32.20 25.1000 134.0

6 6 0.9020 -1.500 0.962 19.90 14.5000 94.8

7 7 0.9210 -1.670 0.917 13.20 8.6800 84.1

8 8 0.9040 -1.720 0.876 9.25 5.3900 76.3

9 9 0.8590 -1.700 0.836 6.80 3.5600 70.5

10 10 0.8330 -1.660 0.831 5.19 2.3800 65.8

11 12 0.8530 -1.480 0.911 3.33 1.1500 58.1

12 14 0.8760 -1.380 0.949 2.35 0.5740 51.9

13 16 0.9070 -1.300 0.970 1.77 0.3090 46.8

14 18 0.9120 -1.240 0.973 1.39 0.1670 42.5

15 20 0.9310 -1.210 0.977 1.14 0.0951 38.7

观察上面的结果,依然是5到6的时候,R^2的值会显著变化

sft$powerEstimate

> sft$powerEstimate

[1] 6

该函数如果发现了R平法大于0.85的power值,就返回最小的那个。

这里返回的是6

为了让结果直观,WGCNA文档把这个图也画出来,

sizeGrWindow(9, 5)

par(mfrow = c(1,2))

cex1 = 0.85

# Scale-free topology fit index as a function of the soft-thresholding power

plot(sft$fitIndices[,1], -sign(sft$fitIndices[,3])*sft$fitIndices[,2],

xlab="Soft Threshold (power)",ylab="Scale Free Topology Model Fit,signed R^2",type="n",

main = paste("Scale independence"));

text(sft$fitIndices[,1], -sign(sft$fitIndices[,3])*sft$fitIndices[,2],

labels=powers,cex=cex1,col="red");

# this line corresponds to using an R^2 cut-off of h

abline(h=0.90,col="red")

# Mean connectivity as a function of the soft-thresholding power

plot(sft$fitIndices[,1], sft$fitIndices[,5],

xlab="Soft Threshold (power)",ylab="Mean Connectivity", type="n",

main = paste("Mean connectivity"))

text(sft$fitIndices[,1], sft$fitIndices[,5], labels=powers, cex=cex1,col="red")

这就是最开始的贴出来的两幅图,为的就是寻找软阈值

两幅图以不同的软阈值作为横坐标。

第一张图,纵坐标是R^2。横线画在了0.85的地方

从图上看,软阈值为6的时候,R平方第一次有了突破,达到了0.9,此时网络已经符合无尺度分布。

第二张图,纵坐标是连通性的平均值,我们已经计算过,他会越来越小。(也就是和基因之间的关联性的平均值,又加上了次幂的结果),必然会越来越小。

思考

WGCNA作者是通过基因相关性,认为使用次幂的形式,将这样一个相关性网络符合幂律形式,进而后续分析。但是涉及到的将相关性的取绝对值等一系列问题,是否取绝对值,这不是数学问题,而是生物学问题,更需要结合具体的生物学问题取舍和证明。

WGCNA: an R package for weighted correlation network analysis | BMC Bioinformatics

WGCNA的分析中为什么要挑选软阈值

小鬼的WGCNA图文详解(一)--软阈值

相关典藏

诺的笔顺
365bet网站平台

诺的笔顺

📅 07-18 👁️‍🗨️ 3842
除了《黑神话》和《三谋》,杭州还有这些研发团队
365bet365游戏

除了《黑神话》和《三谋》,杭州还有这些研发团队

📅 11-03 👁️‍🗨️ 2821
天佑比赛输了,但他们依然赢得了世界的尊重与敬意
365bet网站平台

天佑比赛输了,但他们依然赢得了世界的尊重与敬意

📅 10-22 👁️‍🗨️ 5458