WGCNA其译为加权基因共表达网络分析。该分析方法旨在寻找协同表达的基因模块(module),并探索基因网络与关注的表型之间的关联关系,以及网络中的核心基因。适用于复杂的数据模式,推荐5组(或者15个样品)以上的数据,这里我们把OTU替换成基因其实也就不难理解了。
基本原理
从方法上来讲,WGCNA分为表达量聚类分析和表型关联两部分,主要包括基因之间相关系数计算、基因模块的确定、共表达网络、模块与性状关联四个步骤。
第一步计算任意两个基因之间的相关系数(Person Coefficient)。为了衡量两个基因是否具有相似表达模式,一般需要设置阈值来筛选,高于阈值的则认为是相似的。但是这样如果将阈值设为0.8,那么很难说明0.8和0.79两个是有显著差别的。因此,WGCNA分析时采用相关系数加权值,即对基因相关系数取N次幂,使得网络中的基因之间的连接服从无尺度网络分布(scale-freenetworks),这种算法更具生物学意义。
第二步通过基因之间的相关系数构建分层聚类树,聚类树的不同分支代表不同的基因模块,不同颜色代表不同的模块。基于基因的加权相关系数,将基因按照表达模式进行分类,将模式相似的基因归为一个模块。这样就可以将几万个基因通过基因表达模式被分成了几十个模块,是一个提取归纳信息的过程。
第三步可以利用得到的模块进行:模块与样本之间的相关性、模块与表型数据的相关性,模块的单独分析(功能的富集,注释等)。进一步还可以挖掘模块的核心基因。
专业术语
为了更方便理解后面涉及到单词代表的意思,这里把常用的单词代表的意思贴出来,方便我们查阅。具体内容请看:
原文链接:https://blog.csdn.net/weixin_43700050/article/details/102471309
https://mp.weixin.qq.com/s/PMb2xwADvnMwaipyFXdtzQ
Co-expression network
点代表基因,边代表基因表达相关性。加权是指对相关性值进行冥次运算(冥次的值也就是软阈值 (power, pickSoftThreshold这个函数所做的就是确定合适的power))。无向网络的边属性计算方式为abs(cor(genex, geney)) ^ power;有向网络的边属性计算方式为(1+cor(genex, geney)/2) ^ power; sign hybrid的边属性计算方式为cor(genex, geney)^power if cor>0 else 0。这种处理方式强化了强相关,弱化了弱相关或负相关,使得相关性数值更符合无标度网络特征,更具有生物意义。如果没有合适的power,一般是由于部分样品与其它样品因为某种原因差别太大导致的,可根据具体问题移除部分样品或查看后面的经验值。
Module
模块是高度互连的基因簇。 在无符号共表达网络中,模块对应于具有高度绝对相关性的基因簇。 在有符号网络中,模块对应于正相关的基因。
Connectivity
对于每个基因,连通性定义为与其他网络基因的连接强度之和 ,在共表达网络中,连通性可衡量基因与所有其他网络基因之间的相关性。
Intramodular connectivity
模内连通性测量给定基因相对于特定模块的基因如何连接或共表达。 模内连通性可以解释为模块成员资格的量度。
Module eigengene E
模块特征向量E被定义为给定模块的主成分一。 可以认为是模块中基因表达谱的代表。
Eigengene significance
当可获得微阵列样品特征y(例如病例对照状态或体重)时,可以将模块特征基因与此结果相关联。 相关系数称为特征基因显著性
Module Membership
给定基因表达谱与给定模型的eigengene的相关性。
Hub gene
这个松散定义的术语被用作“高度连接的基因”的缩写。通过定义,共表达模块内部的基因往往具有高度的连通性。
Gene significance GS
为了将外部信息整合到共表达网络中,我们利用了基因显著性方法。抽象地说,GSiGSi GS_iGSi 的绝对值越高,第 ii ii 个基因的生物学意义就越大。例如,GSiGSi GS_iGSi 可以编码通路成员(例如,如果该基因是已知的凋亡基因,则为1,否则为0),敲除必需性或与外部微阵列样品性状的相关性。基因显着性度量也可以通过减去p值的对数来定义。 唯一的要求是,基因显着性0表示该基因对于所关注的生物学问题不重要。 基因显著性可以取正值或负值。
Module significance
模块显著性被定义为给定模块中所有基因的平均绝对基因显著性的度量。 当将基因显着性定义为基因表达与外部性状y的相关性时,此度量往往与模块特征基因与y的相关性高度相关。
Adjacency matrix
邻接矩阵:基因和基因之间的加权相关性值构成的矩阵。
TOM
(Topological overlap matrix):把邻接矩阵转换为拓扑重叠矩阵,以降低噪音和假相关,获得的新距离矩阵,这个信息可拿来构建网络或绘制TOM图。
实战WGCNA
读入数据和加载包
library(WGCNA)
library(igraph)
library(pheatmap)
library(corrplot)
library(ggnetwork)
library(dplyr)
d <- read.table("dan.txt",sep = "\t",header = TRUE,row.names = 1)
otu <- as.data.frame(t(d[1:(nrow(d)-5),]))#otu丰度表:行为样品编号,列为基因也就是我们的otu.
simple_data <- as.data.frame(t(d[(nrow(d)-5):nrow(d),]))#样品形状表,行为样品编号,列为样品对应的处理方式或形状数据,如处理组和对照组或样品的株高、干物质含量等。这两个表行名需一致。
#这里处理组和对照组使用0、1矩阵,0代表无,1代表无。
#筛选相对丰度大于0.01的OTU,自行设置筛选条件。也可不筛选,待会我会展示筛选和不筛选的差别。
otu_a <- otu[,colSums(otu)>0.01]
### WGCNA
# 设定软阈值范围
powers = c(c(1:10), seq(from = 12, to=20, by=2))
# 获得各个阈值下的 R方 和平均连接度
sft = pickSoftThreshold(otu_a, powerVector = powers, verbose = 5)
# 作图:
# 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")
未筛选otu
按相对丰度大于0.01筛选的,可以看到R方升高了(R方是一个衡量网络好坏的重要指标,R方越大说明我们构建的网络越符合无尺度网络),说明网络更好了。其实也很好理解,因为otu矩阵中含有许多0的值,计算时会导致相应的假相关性出现,这时做出来的图很显然是不符合自然规律的。如果我们设置条件筛选了一部分的话,是不是相应的网络就会变得更好一点了。
上文中说到阈值最少也要在0.8以上,这里我数据最好只能到0.7,勉强试试吧。看看能不能跑出来。
# 获得临近矩阵:
softPower <- sft$powerEstimate#取软件推荐的阈值,这里我没有,通过上面那两张图可知道我的阈值应该为4
softPower <- 4#这里手动设置一下
#计算邻接矩阵
adjacency = adjacency(otu_a, power = softPower);
# 将临近矩阵转为 Tom 矩阵
TOM = TOMsimilarity(adjacency);
rownames(TOM) <- colnames(TOM) <- rownames(adjacency)
# 计算基因之间的相异度
dissTOM = 1-TOM
hierTOM = hclust(as.dist(dissTOM),method="average");
#啥啥直方图
k <- softConnectivity(otu_a,power=softPower)
hist(k)
scaleFreePlot(k,main="Check Scale free topology\n")
通过直方图可以看出只有较少的点具有较高的连接性,而大多数的点具有较低的连接性。
图二可以看出k与p(k)成负相关(相关性系数0.63,0.9以上最好),说明选择的β值是可能有问题的,(相关系数r的绝对值一般在0.8以上,认为A和B有强的相关性。0.3到0.8之间,可以认为有弱的相关性。0.3以下,认为没有相关性)这里只是学习所以继续。
# 使用相异度来聚类为gene tree(聚类树):
geneTree = hclust(as.dist(dissTOM), method = "average");
# Plot the resulting clustering tree (dendrogram)
windows()
sizeGrWindow(12,9)
plot(geneTree, xlab="", sub="", main = "Gene clustering on TOM-based dissimilarity",
labels = FALSE, hang = 0.04);
# use dynamic tree to cluster OTU into module
# 使用动态剪切树挖掘模块:模块最小基因数为10
minModuleSize = 10
# 动态切割树:
dynamicMods = cutreeDynamic(dendro = geneTree, distM = dissTOM,
deepSplit = 2, pamRespectsDendro = FALSE,
minClusterSize = minModuleSize);
table(dynamicMods)
dynamicColors <- labels2colors(dynamicMods)
write.table(table(dynamicColors), "mokuai_yanse.txt", quote = F, sep = "
# Plot the resulting clustering tree (dendrogram\t")
otu2colors <- data.frame(OTUID = geneTree$labels, color=dynamicColors, stringsAsFactors = F)
write.table(otu2colors, "otu_mokuai_yanse.txt", quote = F, sep = "\t")
# 拓扑热图:
TOMplot(dissTOM^10,
geneTree,
dynamicColors,
main = "Network heatmap plot")
#计算每个模块的特征向量基因,为某一特定模块第一主成分基因E。代表了该模块内基因表达的整体水平
MEList = moduleEigengenes(otu_a, colors = dynamicColors)
MEs = MEList$eigengenes
# 计算根据模块特征向量基因计算模块相异度:
MEDiss = 1-cor(MEs);
# Cluster module eigengenes
METree = hclust(as.dist(MEDiss), method = "average");
#特征向量基因临近热图:
plotEigengeneNetworks(MEs,
"Eigengene adjacency heatmap",
marHeatmap = c(3,4,2,2),
plotDendrograms = FALSE,
xLabelsAngle = 90)
plot(METree,
main = "Clustering of module eigengenes",
xlab = "",
sub = "")
MEDissThres = 0.5#相异性系数小于0.5,相关性系数大于0.5
# 在聚类图中画出剪切线
abline(h=MEDissThres, col = "red")
#将相关性系数大于0.8的模块合并掉,即相异性系数小于0.2(本次去除0个模块)
merge_modules = mergeCloseModules(otu_a, dynamicColors, cutHeight = MEDissThres, verbose = 3)
# 合并后的颜色:
mergedColors = merge_modules$colors;
as.data.frame(table(mergedColors))
write.table(as.data.frame(table(mergedColors)), "mergedColors_Freq.txt", quote = F, sep = "\t")
otu2colors$mergedcolor <- mergedColors
write.table(otu2colors[,c("OTUID","mergedcolor")], "otu_mokuai_yanse_mergedcolor.txt", quote = F, sep = "\t")
# eigensgens for merged modules
# 新模块的特征向量基因:
mergedMEs = merge_modules$newMEs;
write.table(mergedMEs, "yangpin_mergedMEs_cor.txt", quote = F, sep = "\t")
write.table(cor(mergedMEs), "mergedMEs_cor.txt", quote = F, sep = "\t")
plotDendroAndColors(geneTree, cbind(dynamicColors, mergedColors),
c("Dynamic Tree Cut", "Merged dynamic"),
dendroLabels = FALSE, hang = 0.03,
addGuide = TRUE, guideHang = 0.05)
画出样本聚类图(上)与样本性状热图(下)
# 画出样本聚类图(上)与样本性状热图(下):
traitColors = numbers2colors(simple_data, signed = TRUE,centered=TRUE);
#计算样品的树
yangping <- as.data.frame(t(otu_a))
adjacency_sim = adjacency(yangping, type = "unsigned")
sampleTree = hclust(as.dist(adjacency_sim), method = "average")
plotDendroAndColors(sampleTree,
traitColors,
groupLabels = names(simple_data),
rowTextAlignment = "right-justified",
addTextGuide = TRUE ,
hang = 0.03,
dendroLabels = NULL, # 是否显示树labels
addGuide = FALSE, # 显示虚线
guideHang = 0.05,
main = "Sample dendrogram and trait heatmap")
#模块与样本性状相关性热图,行表示模块,列表示性状。方块里的值表示相关性和pvalue.
moduleTraitCor_noFP <- cor(mergedMEs, simple_data[,1:6], use = "p");
moduleTraitPvalue_noFP = corPvalueStudent(moduleTraitCor_noFP, 24);
sizeGrWindow(9,9)
textMatrix_noFP <- paste(signif(moduleTraitCor_noFP, 2), "\n(", signif(moduleTraitPvalue_noFP, 1), ")", sep = "");
par(mar = c(10, 8.5, 3, 3));
labeledHeatmap(Matrix = moduleTraitCor_noFP,
xLabels = names(simple_data[,1:6]),
yLabels = names(mergedMEs),
ySymbols = names(mergedMEs),
colorLabels = FALSE,
colors = blueWhiteRed(50),
textMatrix = textMatrix_noFP,
setStdMargins = FALSE,
cex.text = 0.65,
zlim = c(-1,1),
main = paste("Module-trait relationships"))
#根据性状与模块特征向量基因的相关性及pvalue来挖掘与性状相关的模块
cor_ADR <- signif(WGCNA::cor(simple_data,mergedMEs,use="p",method="pearson"),5)
p.values <- corPvalueStudent(cor_ADR,nSamples=nrow(simple_data))
Freq_MS_max_cor <- which.max(abs(cor_ADR["Freq",-which(colnames(cor_ADR) == "MEgrey")]))
Freq_MS_max_p <- which.min(p.values["Freq",-which(colnames(p.values) == "MEgrey")])
#根据基因网络显著性,也就是性状与每个基因表达量相关性在各个模块的均值作为该性状在该模块的显著性,显著性最大的那个模块与该性状最相关:
GS1 <- as.numeric(WGCNA::cor(simple_data[,2],otu_a,use="p",method="pearson"))#2代表你要研究的性状
# 显著性是绝对值:
GeneSignificance <- abs(GS1)
# 获得该性状在每个模块中的显著性:
ModuleSignificance <- tapply(GeneSignificance,mergedColors,mean,na.rm=T)
数值越大,越相关,由此可知为red模块与protein相关,从上面模块与性状相关性表也能看出来。
寻找与该性状相关的枢纽基因(hub genes),首先计算基因的内部连接度和模块身份,内部连接度衡量的是基因在模块内部的地位,而模块身份表明基因属于哪个模块。
# 计算每个基因模块内部连接度,也就是基因直接两两加权相关性。
ADJ1=abs(cor(otu_a,use="p"))^softPower
# 根据上面结果和基因所属模块信息获得连接度:
# 整体连接度 kTotal,模块内部连接度:kWithin,kOut=kTotal-kWithin, kDiff=kIn-kOut=2*kIN-kTotal
colorh1 = mergedColors
Alldegrees1=intramodularConnectivity(ADJ1, colorh1)
# 注意模块内基于特征向量基因连接度评估模块内其他基因: de ne a module eigengene-based connectivity measure for each gene as the correlation between a the gene expression and the module eigengene
# 如 brown 模块内:kM Ebrown(i) = cor(xi, MEbrown) , xi is the gene expression pro le of gene i and M Ebrown is the module eigengene of the brown module
# 而 module membership 与内部连接度不同。MM 衡量了基因在全局网络中的位置。
datKME=signedKME(otu_a, mergedMEs, outputColumnName="MM.")#基因与模块的相关性
#查看内部连接度和 MM直接的关系,以red为例
which.color="red";
restrictGenes=colorh1==which.color
windows()
sizeGrWindow(12,9)
verboseScatterplot(Alldegrees1$kWithin[ restrictGenes],
(datKME[restrictGenes, paste("MM.", which.color, sep="")])^4,
col=which.color,
xlab="Intramodular Connectivity",
ylab="(Module Membership)^4")
#画所有模块
colorlevels=unique(colorh1)
sizeGrWindow(9,6)
par(mfrow=c(2,as.integer(0.5+length(colorlevels)/2)))
par(mar = c(4,5,3,1))
for (i in c(1:length(colorlevels))) { whichmodule=colorlevels[[i]]; restrict1 = (colorh1==whichmodule);
verboseScatterplot(Alldegrees1$kWithin[restrict1], GeneSignificance[restrict1], col=colorh1[restrict1],
main=whichmodule, xlab = "Connectivity", ylab = "Gene Significance", abline = TRUE) }
#我们使用2个标准来筛选枢纽基因:基因与指定模块显著性 > 0.2, red Module membership value > 0.8,
GS_spe=as.numeric(cor(simple_data$`milk protein`,otu_a, use="p")) #选择的样品性状simple_data$`milk protein`与基因之间的相关性
GeneSignificance_spe <- abs(GS_spe)
# 基于显著性和MM计算每个基因与 指定simple_data$`milk protein` 的关联,结果包括p, q, cor, z,
NS1=networkScreening(y=simple_data$`milk protein`,
datME=mergedMEs,
datExpr=otu_a,
oddPower=3,
blockSize=1000,
minimumSampleSize=4,
addMEy=TRUE,a
removeDiag=FALSE,
weightESy=0.5)
rownames(NS1) <- colnames(otu_a)
nGenes=ncol(datExpr)
nSample=nrow(datExpr)
#选基因
datME=moduleEigengenes(datExpr,moduleColors,trapErrors=FALSE)$eigengenes
HG=networkScreeningGS(datExpr,datME,t(geneTraitSignificance),oddPower = 3,blockSize = 1000,minimumSampleSize = 4, addGS = TRUE)
GeneResultsNetworkScreening=data.frame(GeneName=row.names(HG),HG)
write.table(GeneResultsNetworkScreening,file="HubGene.txt",row.names=F,sep="\t")
# 根据 基因与指定性状的直接相关性(biserial.cor),模块身份,和加权相关性 筛选基因:
FilterGenes_spe = ((GeneSignificance_spe > 0.2) & (abs(datKME$MM.red)>0.8)
table(FilterGenes_spe)
# 找到满足上面条件的基因:
trait_hubGenes_spe <- colnames(otu_a)[FilterGenes_spe]
这里只找到6个,不做讨论,下面导出hub gene的网络图
# hub 基因热图:
plotNetworkHeatmap(otu_a,
plotGenes = paste("X",trait_hubGenes_spe,sep = ""),
networkType = "unsigned",
useTOM = TRUE,
power=softPower,
main="unsigned correlations")
# 导出枢纽基因到 Cytoscape
hubGene_TOM <- TOM[FilterGenes_spe,FilterGenes_spe]
dimnames(hubGene_TOM) = list(colnames(otu_a)[FilterGenes_spe], colnames(otu_a)[FilterGenes_spe])
cyt = exportNetworkToCytoscape(hubGene_TOM,
edgeFile = paste("CytoscapeInput-edges-", paste(which.color, collapse="-"), ".txt", sep=""),
nodeFile = paste("CytoscapeInput-nodes-", paste(which.color, collapse="-"), ".txt", sep=""),
weighted = TRUE,
threshold = 0.02,
nodeNames = trait_hubGenes_spe,
altNodeNames = trait_hubGenes_spe,
nodeAttr = mergedColors[FilterGenes_spe]
)
尝试用R语言画网络图
# plot whole network
adj <- adjacency
adj[adj < 0.15] <- 0
ig <- graph.adjacency(adj, weighted = T, mode="upper", diag = F)
# display module
gene2colors$newcolor <- recode(gene2colors$mergedcolor,
tan = "grey",
black = "grey",
turquoise = "grey",
purple = "grey",
salmon = "grey",
cyan = "grey",
magenta = "grey",
greenyellow = "grey")
V(ig)$color <- gene2colors$mergedcolor
ig_g <- ig
## Add edges with high weight between all nodes in the same group
for(i in unique(V(ig)$color)) {
GroupV = which(V(ig)$color == i)
Vdegree <- degree(ig)[GroupV]
maxV <- GroupV[which.max(Vdegree)]
minV <- GroupV[Vdegree == 0]
edge <- c(rbind(rep(maxV, length(minV)), minV))
ig_g = add_edges(ig_g, edge, attr=list(weight=0.2))
}
windows()
sizeGrWindow(12,9)
plot(ig,
layout=layout_with_fr(ig_g),
vertex.size=3,
vertex.label=NA,
vertex.shape="circle",
edge.width=0.01, main = "Whole network")
# plot each module
blue_group <- gene2colors$OTUID[gene2colors$mergedcolor == "blue"]
ig_blue <- induced_subgraph(ig, blue_group)
V(ig_blue)$size <- log(degree(ig_blue) + 2, base = 2)
plot(ig_blue,
layout=layout_with_fr(ig_blue),
vertex.label = NA,
vertex.color = "blue",
vertex.shape="circle",
edge.width=0.01,
main = "Module blue", alpha = 0.1)
参考资料
WGCNA实例分析及解读(附代码)
https://www.jianshu.com/p/25905a905086
https://horvath.genetics.ucla.edu/html/CoexpressionNetwork/Rpackages/WGCNA/index.html
官方网站的学习教程,共7篇含代码和实例,有需要的小伙伴留言或关注微信公众号:Amoy数据分析。