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 signi?cance
當可獲得微陣列樣品特征y(例如病例對照狀態或體重)時,可以將模塊特征基因與此結果相關聯。 相關系數稱為特征基因顯著性
Module Membership
給定基因表達譜與給定模型的eigengene的相關性。
Hub gene
這個松散定義的術語被用作“高度連接的基因”的縮寫。通過定義,共表達模塊內部的基因往往具有高度的連通性。
Gene signi?cance GS
為了將外部信息整合到共表達網絡中,我們利用了基因顯著性方法。抽象地說,GSiGSi GS_iGSi? 的絕對值越高,第 ii ii 個基因的生物學意義就越大。例如,GSiGSi GS_iGSi? 可以編碼通路成員(例如,如果該基因是已知的凋亡基因,則為1,否則為0),敲除必需性或與外部微陣列樣品性狀的相關性。基因顯著性度量也可以通過減去p值的對數來定義。 唯一的要求是,基因顯著性0表示該基因對于所關注的生物學問題不重要。 基因顯著性可以取正值或負值。
Module signi?cance
模塊顯著性被定義為給定模塊中所有基因的平均絕對基因顯著性的度量。 當將基因顯著性定義為基因表達與外部性狀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實例分析及解讀(附代碼)
http://www.lxweimin.com/p/25905a905086
https://horvath.genetics.ucla.edu/html/CoexpressionNetwork/Rpackages/WGCNA/index.html
官方網站的學習教程,共7篇含代碼和實例,有需要的小伙伴留言或關注微信公眾號:Amoy數據分析。