返回分析流程中心

Pipeline Detail

RNA-Seq转录组结构与网络

WGCNA 共表达网络分析

面向 bulk RNA-seq 表达矩阵的 WGCNA 共表达网络流程,覆盖表达矩阵预处理、软阈值选择、模块识别、模块-性状相关、hub gene 挖掘、富集分析与可视化解释。

创建时间
2026/6/3
分析难度
中级
推荐场景
转录组分析
预计耗时
1-3 天

Metadata

流程元数据

先看应用场景、输入输出和工具依赖,再进入正文命令细节。

Difficulty

中级

Scenario

转录组分析

Estimated Time

1-3 天

Tools

DESeq2WGCNA

Inputs

FASTQTPMexpression matrix

Outputs

heatmaphub genesreport

Workflow DAG

流程图

用步骤节点快速理解这个分析从原始数据到结果报告的流转关系。

STEP 1

表达矩阵与性状表

STEP 2

VST/TPM/log2 转换

STEP 3

低表达与低变异过滤

STEP 4

样本聚类与离群检测

STEP 5

软阈值选择

STEP 6

网络构建与 TOM

STEP 7

模块识别与合并

STEP 8

模块-性状相关

STEP 9

hub gene 筛选

STEP 10

富集与网络可视化

Protocol

流程文档

正文保留 Markdown 排版、代码语言标识和表格样式,适合边学边复现。

WGCNA 共表达网络分析

一、适用场景

WGCNA,全称 Weighted Gene Co-expression Network Analysis,是一种基于基因表达相关性构建加权共表达网络的方法。它的核心思想是:如果一批基因在多个样本中的表达模式高度一致,那么这些基因可能受到共同调控,或者参与同一类生物过程。

适用于:

  • bulk RNA-seq、microarray、蛋白组、代谢组等连续表达矩阵。
  • 寻找与表型、处理、时间、病理指标或生理指标相关的基因模块。
  • 从大量表达基因中筛选模块 hub genes。
  • 将差异表达分析从“单基因列表”扩展到“基因网络模块”层面。
  • 多时间点、多组织、多处理组项目中的表达模式归纳。

不适合直接套用:

  • 样本数过少。WGCNA 对样本数敏感,推荐至少 15 个样本,较稳定的网络通常需要 20-30 个以上样本。
  • 没有连续表达变化或样本差异很小的项目。
  • 只想做两组差异表达时,DESeq2/edgeR 更直接。
  • 原始 count 未经过方差稳定转换时,不建议直接输入 WGCNA。

二、WGCNA 能回答什么问题

问题WGCNA 输出怎么解释
哪些基因表达模式相似?co-expression modules同一模块内基因具有相似表达趋势
哪些模块和性状最相关?module-trait correlation heatmap相关系数越高,模块越可能与性状相关
模块里的代表表达趋势是什么?module eigengene, ME可以理解为该模块的第一主成分
模块里最核心的基因是谁?hub genes模块内连接度高,且与性状相关的基因
模块代表什么生物功能?GO/KEGG/GSEA enrichment解释模块背后的通路和过程

三、关键概念图例

概念类比生信含义
Gene网络节点一个基因
Edge连线两个基因表达相关
Weight连线粗细相关性强弱经过软阈值转换后的权重
Module颜色社区一组共表达基因,例如 turquoise、blue、brown
Module eigengene模块代表曲线模块整体表达趋势
Trait外部性状处理组、表型值、时间点、临床指标
Hub gene核心节点模块内连接度高且与性状相关的候选关键基因

示意:

Trait: drought severity
        |
        | corr = 0.82, p = 1e-05
        v
turquoise module eigengene
        |
        | high module membership
        v
Hub genes: NAC1, DREB2A, HSP70, ...

解释:如果 turquoise 模块和干旱程度高度正相关,且模块中的 DREB2A 同时具有较高 module membership 和 gene significance,那么它就是值得优先关注的候选 hub gene。

四、整体流程图

flowchart TD
    A[RNA-seq count / TPM matrix] --> B[VST / log2(TPM+1) 转换]
    B --> C[低表达和低变异基因过滤]
    C --> D[样本聚类检测离群样本]
    D --> E[选择 soft-threshold power]
    E --> F[构建 adjacency matrix]
    F --> G[计算 TOM similarity]
    G --> H[层次聚类识别 modules]
    H --> I[合并相似 modules]
    I --> J[计算 module eigengenes]
    J --> K[模块-性状相关热图]
    K --> L[筛选 hub genes]
    L --> M[GO/KEGG 富集和 Cytoscape 网络]

五、输入文件与目录建议

wgcna_project/
├── 00_metadata/
│   └── traits.csv
├── 01_expression/
│   ├── raw_counts.csv
│   ├── vst_matrix.csv
│   └── filtered_expr.csv
├── 02_qc/
│   ├── sample_clustering.pdf
│   └── soft_power.pdf
├── 03_wgcna/
│   ├── network.RData
│   ├── module_genes.csv
│   ├── module_trait_correlation.csv
│   └── hub_genes.csv
├── 04_enrichment/
├── 05_cytoscape/
└── report/

表达矩阵格式:

gene_idCtrl_1Ctrl_2Treat_1Treat_2
GeneA10.211.520.121.3
GeneB3.22.91.11.4

WGCNA 的 R 输入通常要求:

行 = 样本
列 = 基因

性状表 traits.csv

sample_idconditiondrought_scorebiomass
Ctrl_1Ctrl012.3
Ctrl_2Ctrl013.1
Treat_1Treat86.5
Treat_2Treat95.9

六、表达矩阵预处理

1. 从 DESeq2 count 生成 VST 矩阵

对于 RNA-seq raw count,推荐先用 DESeq2 做 VST 或 rlog 变换,让低表达和高表达基因的方差更稳定。

library(DESeq2)
library(tidyverse)

count_data <- read.csv("01_expression/raw_counts.csv", row.names = 1, check.names = FALSE)
trait_data <- read.csv("00_metadata/traits.csv", row.names = 1)

count_data <- count_data[, rownames(trait_data)]

dds <- DESeqDataSetFromMatrix(
  countData = round(as.matrix(count_data)),
  colData = trait_data,
  design = ~ 1
)

keep <- rowSums(counts(dds) >= 10) >= 3
dds <- dds[keep, ]

vsd <- vst(dds, blind = TRUE)
vst_matrix <- assay(vsd)

write.csv(vst_matrix, "01_expression/vst_matrix.csv")

也可以使用 TPM:

tpm <- read.csv("01_expression/tpm_matrix.csv", row.names = 1, check.names = FALSE)
log_tpm <- log2(tpm + 1)
write.csv(log_tpm, "01_expression/log2_tpm_matrix.csv")

建议:

  • WGCNA 不建议直接输入 raw count。
  • 如果是 DESeq2 流程,优先使用 vst
  • 如果只有 TPM/FPKM,可以使用 log2(TPM + 1)
  • 做 WGCNA 前应去掉低表达和低变异基因,减少噪音和计算量。

2. 过滤低变异基因

expr <- read.csv("01_expression/vst_matrix.csv", row.names = 1, check.names = FALSE)

gene_mad <- apply(expr, 1, mad)
top_genes <- names(sort(gene_mad, decreasing = TRUE))[1:min(8000, length(gene_mad))]
expr_filtered <- expr[top_genes, ]

write.csv(expr_filtered, "01_expression/filtered_expr.csv")

常见策略:

策略说明
保留 MAD 最高的 5000-10000 个基因常用、稳定、适合样本数中等项目
保留表达量前 50% 的基因简单但可能保留低变异 housekeeping genes
保留差异基因再做 WGCNA可行但有偏,会只看差异相关网络

七、样本聚类与离群检测

WGCNA 对离群样本非常敏感,必须先做样本聚类。

library(WGCNA)

options(stringsAsFactors = FALSE)
allowWGCNAThreads()

expr <- read.csv("01_expression/filtered_expr.csv", row.names = 1, check.names = FALSE)
datExpr <- as.data.frame(t(expr))

gsg <- goodSamplesGenes(datExpr, verbose = 3)
if (!gsg$allOK) {
  datExpr <- datExpr[gsg$goodSamples, gsg$goodGenes]
}

sample_tree <- hclust(dist(datExpr), method = "average")

pdf("02_qc/sample_clustering.pdf", width = 10, height = 6)
plot(sample_tree, main = "Sample clustering to detect outliers", sub = "", xlab = "")
dev.off()

如果某个样本明显远离所有同组样本,应回看:

  • FastQC/MultiQC 质量。
  • mapping rate。
  • library size。
  • 样本标签是否混淆。
  • PCA 是否也显示离群。

不要因为结果“不好看”随意删除样本,必须有 QC 证据。

八、软阈值 soft-threshold power 选择

WGCNA 不用硬阈值把相关性切成 0/1,而是用软阈值把相关性转换为网络连接权重。

powers <- c(1:10, seq(12, 30, by = 2))

sft <- pickSoftThreshold(
  datExpr,
  powerVector = powers,
  networkType = "signed",
  verbose = 5
)

pdf("02_qc/soft_power.pdf", width = 10, height = 5)
par(mfrow = c(1, 2))

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 = "Scale independence"
)
text(
  sft$fitIndices[, 1],
  -sign(sft$fitIndices[, 3]) * sft$fitIndices[, 2],
  labels = powers,
  col = "red"
)
abline(h = 0.8, col = "red")

plot(
  sft$fitIndices[, 1],
  sft$fitIndices[, 5],
  xlab = "Soft Threshold power",
  ylab = "Mean connectivity",
  type = "n",
  main = "Mean connectivity"
)
text(sft$fitIndices[, 1], sft$fitIndices[, 5], labels = powers, col = "red")
dev.off()

选择原则:

指标建议
scale-free topology fit R²通常希望接近或超过 0.8
mean connectivity不要过低,否则网络太稀疏
signed network常用于保留正负相关方向,power 往往比 unsigned 更高
样本数较少不要机械追求 R²,结合模块稳定性判断

示例解释:

如果 power = 12 时 R² 达到 0.82,mean connectivity 仍然不低,
可以选择 softPower = 12。
如果 R² 一直达不到 0.8,选择曲线趋于平稳处,并在报告中说明。

九、构建网络和识别模块

1. 自动网络构建

softPower <- 12

net <- blockwiseModules(
  datExpr,
  power = softPower,
  networkType = "signed",
  TOMType = "signed",
  minModuleSize = 30,
  reassignThreshold = 0,
  mergeCutHeight = 0.25,
  numericLabels = TRUE,
  pamRespectsDendro = FALSE,
  saveTOMs = TRUE,
  saveTOMFileBase = "03_wgcna/TOM",
  verbose = 3
)

moduleColors <- labels2colors(net$colors)
MEs <- net$MEs

save(datExpr, net, moduleColors, MEs, file = "03_wgcna/network.RData")

关键参数:

参数说明
networkType = "signed"保留正相关方向,更适合生物解释
TOMType = "signed"基于 signed network 计算拓扑重叠
minModuleSize最小模块大小,常用 30-50
mergeCutHeight合并相似模块,0.25 表示 eigengene 相关性约 0.75
power软阈值

2. 模块树图

pdf("03_wgcna/gene_dendrogram_modules.pdf", width = 12, height = 6)
plotDendroAndColors(
  net$dendrograms[[1]],
  moduleColors[net$blockGenes[[1]]],
  "Module colors",
  dendroLabels = FALSE,
  hang = 0.03,
  addGuide = TRUE,
  guideHang = 0.05
)
dev.off()

图例解释:

上方树状图:基因按照共表达相似性聚类。
下方颜色条:WGCNA 分配的模块颜色。
同一颜色中的基因表达模式更相似。
grey 模块通常表示未归入明确模块的基因。

十、模块-性状相关分析

1. 准备性状矩阵

trait_data <- read.csv("00_metadata/traits.csv", row.names = 1)
trait_data <- trait_data[rownames(datExpr), ]

trait_data$condition_binary <- ifelse(trait_data$condition == "Treat", 1, 0)

numeric_traits <- trait_data |>
  dplyr::select(where(is.numeric))

2. 模块与性状相关热图

MEs0 <- moduleEigengenes(datExpr, moduleColors)$eigengenes
MEs <- orderMEs(MEs0)

module_trait_cor <- cor(MEs, numeric_traits, use = "p")
module_trait_pvalue <- corPvalueStudent(module_trait_cor, nSamples = nrow(datExpr))

text_matrix <- paste(
  signif(module_trait_cor, 2),
  "
(",
  signif(module_trait_pvalue, 1),
  ")",
  sep = ""
)
dim(text_matrix) <- dim(module_trait_cor)

pdf("03_wgcna/module_trait_heatmap.pdf", width = 9, height = 8)
labeledHeatmap(
  Matrix = module_trait_cor,
  xLabels = names(numeric_traits),
  yLabels = names(MEs),
  ySymbols = names(MEs),
  colorLabels = FALSE,
  colors = blueWhiteRed(50),
  textMatrix = text_matrix,
  setStdMargins = FALSE,
  cex.text = 0.8,
  zlim = c(-1, 1),
  main = "Module-trait relationships"
)
dev.off()

write.csv(module_trait_cor, "03_wgcna/module_trait_correlation.csv")
write.csv(module_trait_pvalue, "03_wgcna/module_trait_pvalue.csv")

热图读法:

示例解释
MEturquoise vs drought_score: 0.82 (1e-05)turquoise 模块和干旱程度显著正相关
MEblue vs biomass: -0.71 (0.002)blue 模块表达越高,biomass 越低
MEgrey未归类基因模块,一般不作为重点解释

十一、筛选 hub genes

hub gene 通常同时满足:

  1. 属于目标模块。
  2. 与模块 eigengene 高相关,即 module membership 高。
  3. 与目标性状高相关,即 gene significance 高。
  4. 有合理生物学功能或文献支持。
target_module <- "turquoise"
target_trait <- "drought_score"

module_genes <- moduleColors == target_module

MM <- as.data.frame(cor(datExpr, MEs, use = "p"))
MMPvalue <- as.data.frame(corPvalueStudent(as.matrix(MM), nrow(datExpr)))

GS <- as.data.frame(cor(datExpr, numeric_traits[[target_trait]], use = "p"))
GSPvalue <- as.data.frame(corPvalueStudent(as.matrix(GS), nrow(datExpr)))

gene_info <- data.frame(
  gene_id = colnames(datExpr),
  module = moduleColors,
  module_membership = MM[[paste0("ME", target_module)]],
  module_membership_pvalue = MMPvalue[[paste0("ME", target_module)]],
  gene_significance = GS[, 1],
  gene_significance_pvalue = GSPvalue[, 1]
)

hub_genes <- gene_info |>
  dplyr::filter(
    module == target_module,
    abs(module_membership) >= 0.8,
    abs(gene_significance) >= 0.5
  ) |>
  dplyr::arrange(desc(abs(module_membership)), desc(abs(gene_significance)))

write.csv(gene_info, "03_wgcna/all_gene_module_membership.csv", row.names = FALSE)
write.csv(hub_genes, "03_wgcna/hub_genes_turquoise.csv", row.names = FALSE)

MM-GS 散点图

library(ggplot2)
library(ggrepel)

plot_df <- gene_info |>
  dplyr::filter(module == target_module) |>
  dplyr::mutate(label = ifelse(row_number() <= 10, gene_id, NA))

ggplot(plot_df, aes(abs(module_membership), abs(gene_significance))) +
  geom_point(alpha = 0.7, color = target_module) +
  geom_text_repel(aes(label = label), max.overlaps = 20) +
  theme_bw() +
  labs(
    x = paste0("Module Membership in ", target_module),
    y = paste0("Gene Significance for ", target_trait),
    title = "Hub gene screening"
  )

ggsave("03_wgcna/MM_vs_GS_turquoise.pdf", width = 7, height = 6)

图例解释:

x 轴越靠右:基因越能代表该模块。
y 轴越靠上:基因越和目标性状相关。
右上角基因:优先候选 hub genes。

十二、导出 Cytoscape 网络

如果需要给读者展示模块内部网络,可以导出 Cytoscape 文件。

load("03_wgcna/network.RData")

target_module <- "turquoise"
module_genes <- moduleColors == target_module
module_expr <- datExpr[, module_genes]

TOM <- TOMsimilarityFromExpr(
  module_expr,
  power = softPower,
  networkType = "signed",
  TOMType = "signed"
)

dimnames(TOM) <- list(colnames(module_expr), colnames(module_expr))

exportNetworkToCytoscape(
  TOM,
  edgeFile = "05_cytoscape/turquoise_edges.txt",
  nodeFile = "05_cytoscape/turquoise_nodes.txt",
  weighted = TRUE,
  threshold = 0.08,
  nodeNames = colnames(module_expr),
  nodeAttr = target_module
)

Cytoscape 图例建议:

元素建议含义
节点大小module membership 或 intramodular connectivity
节点颜色gene significance 或 log2FC
边粗细TOM weight
标签top hub genes

十三、模块功能富集

library(clusterProfiler)
library(org.Hs.eg.db)

target_genes <- gene_info |>
  dplyr::filter(module == "turquoise") |>
  dplyr::pull(gene_id)

entrez <- mapIds(
  org.Hs.eg.db,
  keys = target_genes,
  column = "ENTREZID",
  keytype = "ENSEMBL",
  multiVals = "first"
) |>
  na.omit()

ego <- enrichGO(
  gene = entrez,
  OrgDb = org.Hs.eg.db,
  keyType = "ENTREZID",
  ont = "BP",
  pAdjustMethod = "BH",
  pvalueCutoff = 0.05
)

write.csv(as.data.frame(ego), "04_enrichment/turquoise_GO_BP.csv", row.names = FALSE)

解释方式:

  • 如果 turquoise 模块与干旱强度正相关,且富集到 ABA response、water deprivation、oxidative stress,可以推测该模块参与干旱响应。
  • 如果 blue 模块与 biomass 负相关,且富集到 defense response,可能说明胁迫防御激活伴随生长抑制。

十四、一个完整解释例子

假设得到下面结果:

模块相关性最高性状corp-value富集功能代表 hub gene
turquoisedrought_score0.821e-05response to water deprivationDREB2A, HSP70
bluebiomass-0.710.002defense responseWRKY33, PR1
brownchlorophyll0.660.006photosynthesisLHCA1, RBCS

可以这样写结论:

turquoise 模块与干旱评分显著正相关,说明该模块基因整体随干旱程度升高而上调。
该模块富集于水分胁迫和 ABA 响应通路,其中 DREB2A 同时具有较高 module membership 和 gene significance,
因此可作为后续验证的候选调控基因。

十五、常见问题与排查

问题可能原因建议
模块数量很少过滤太严格、样本差异弱、mergeCutHeight 太低放宽过滤,调整 minModuleSizemergeCutHeight
grey 模块过大很多基因无法归入稳定模块检查表达矩阵质量和低变异基因过滤
soft power 无法达到 R² 0.8样本数少、离群样本、批次效应检查样本聚类,不要机械追求阈值
模块和性状全不相关性状编码不合理或生物信号弱检查 trait 表和样本顺序
hub gene 全是 housekeeping genes输入基因过滤不合理去掉低变异/低信息基因
网络太大难以画图节点太多、边阈值太低只导出目标模块 top edges

十六、主要交付物

  • VST/log2 transformed expression matrix
  • 样本聚类树和离群样本检查图
  • soft-threshold power 选择图
  • gene dendrogram and module color 图
  • module eigengene 表
  • module-trait correlation heatmap
  • 每个模块的基因清单
  • 目标模块 hub gene 表
  • MM-GS scatter plot
  • 模块 GO/KEGG 富集结果
  • Cytoscape network edge/node 文件
  • 解释性报告和候选基因清单

十七、参考资料

  • WGCNA 官方教程:网络构建、模块识别、模块-性状关系和 hub gene 筛选。
  • WGCNA BMC Bioinformatics 原始论文:介绍 weighted correlation network、模块检测和拓扑性质。
  • DESeq2 / Bioconductor RNA-seq workflow:用于 RNA-seq count 的 VST/rlog 方差稳定转换。