跳转至

770. 基因共表达网络WGCNA进阶

一句话概述:WGCNA进阶分析包括签名网络(signed network)、模块保存性检验、多数据集比较——就像从"基础关系网"升级到"深度社交分析",不仅知道谁跟谁一起,还能验证这些关系在不同环境下是否稳定。


核心知识点速查表

概念白话解释关键工具
Signed network区分正相关和负相关推荐使用
软阈值(β)控制网络的scale-free特性pickSoftThreshold
模块保存性模块在其他数据集中是否稳定modulePreservation
模块-表型关联模块与临床性状的相关性Module-trait关系
Hub基因模块内连接度最高的基因kME值
bicor双权重中位相关(稳健)替代Pearson

一、进阶概念

1.1 Signed vs Unsigned Network

Unsigned network(无符号网络):
  相关性取绝对值 → |cor(A,B)|
  问题:正相关和负相关的基因被放在同一个模块
  → 生物学上不合理(激活和抑制的基因不应在一起)

Signed network(签名网络,推荐):
  相关性保留符号 → (1 + cor(A,B)) / 2
  → 只有正相关的基因才可能在同一个模块
  → 负相关的基因在不同模块
  → 生物学解释更合理

Signed hybrid(签名混合,折中):
  正相关 → cor(A,B)^β
  负相关 → 0
  → 忽略负相关但不混入正相关模块

1.2 相关性方法选择

Pearson相关(默认):
  假设线性关系 + 正态分布
  对异常值敏感

Biweight midcorrelation (bicor,推荐):
  稳健中位相关,对异常值不敏感
  WGCNA开发者推荐
  函数:WGCNA::bicor()

二、Signed Network构建

# ===== WGCNA Signed Network完整流程 =====
library(WGCNA)  # 加载WGCNA

# ===== Step 1: 数据准备 =====
options(stringsAsFactors = FALSE)  # 字符串不自动转因子
allowWGCNAThreads(8)               # 启用多线程

# 读取表达数据(基因为列,样本为行)
datExpr <- read.csv("expression_matrix.csv", row.names=1)
datExpr <- t(datExpr)  # 转置为样本×基因

# 检查缺失值和异常样本
gsg <- goodSamplesGenes(datExpr, verbose=3)  # 检查数据质量
if (!gsg$allOK) {
  datExpr <- datExpr[gsg$goodSamples, gsg$goodGenes]  # 移除问题数据
}

# 样本聚类检查异常值
sampleTree <- hclust(dist(datExpr), method="average")
plot(sampleTree, main="Sample Clustering to Detect Outliers")

# ===== Step 2: 选择软阈值(Signed Network)=====
powers <- c(1:20)  # 候选软阈值

# 关键:networkType = "signed"
sft <- pickSoftThreshold(
  datExpr,
  powerVector = powers,
  networkType = "signed",       # 签名网络(重要!)
  corFnc = "bicor",             # 使用bicor相关(推荐)
  verbose = 5
)

# 绘制拟合图
par(mfrow=c(1,2))
# 左图:Scale-free topology fit index
plot(sft$fitIndices[,1], -sign(sft$fitIndices[,3])*sft$fitIndices[,2],
     xlab="Soft Threshold (power)", ylab="Scale Free Topology Model Fit",
     main="Scale independence", type="n")
text(sft$fitIndices[,1], -sign(sft$fitIndices[,3])*sft$fitIndices[,2],
     labels=powers, col="red")
abline(h=0.85, col="red")  # R²>0.85的阈值线

# 右图:Mean connectivity
plot(sft$fitIndices[,1], sft$fitIndices[,5],
     xlab="Soft Threshold (power)", ylab="Mean Connectivity",
     main="Mean connectivity", type="n")
text(sft$fitIndices[,1], sft$fitIndices[,5], labels=powers, col="red")

# 选择β值(R²>0.85的最小power,signed通常在10-14之间)
softPower <- sft$powerEstimate
cat("Selected soft threshold:", softPower, "\n")

# ===== Step 3: 一步构建网络和模块 =====
net <- blockwiseModules(
  datExpr,
  power = softPower,                # 软阈值
  networkType = "signed",           # 签名网络
  corType = "bicor",                # bicor相关
  TOMType = "signed",               # 签名TOM
  minModuleSize = 30,               # 最小模块大小
  reassignThreshold = 0,            # 重分配阈值
  mergeCutHeight = 0.25,            # 模块合并阈值
  numericLabels = TRUE,             # 数字标签
  pamRespectsDendro = FALSE,        # PAM设置
  saveTOMs = TRUE,                  # 保存TOM矩阵
  saveTOMFileBase = "signed_TOM",   # TOM文件名前缀
  verbose = 3,
  maxBlockSize = 20000              # 最大块大小
)

# 查看模块
table(net$colors)  # 每个模块的基因数
# 0    1    2    3    4    5    ...
# 500  1200 800  600  400  350  ...
# 模块0 = 灰色 = 未分配的基因

# 绘制模块树状图
mergedColors <- labels2colors(net$colors)  # 数字转颜色
plotDendroAndColors(
  net$dendrograms[[1]],
  mergedColors[net$blockGenes[[1]]],
  "Module colors",
  dendroLabels = FALSE,
  main = "Gene Dendrogram and Module Colors (Signed Network)"
)

三、模块保存性检验

# ===== Module Preservation Analysis =====
# 检验一个数据集中发现的模块在另一个数据集中是否保存

# 数据集1: 参考数据(已建好网络)
# 数据集2: 测试数据(验证模块是否存在)

# 准备多数据集格式
multiExpr <- list(
  Reference = list(data = datExpr_ref),   # 参考数据集
  Test = list(data = datExpr_test)        # 测试数据集
)

# 参考数据集的模块颜色
multiColor <- list(
  Reference = moduleColors_ref            # 参考数据的模块标签
)

# 运行模块保存性检验
mp <- modulePreservation(
  multiData = multiExpr,               # 多数据集
  multiColor = multiColor,             # 模块颜色
  referenceNetworks = 1,               # 参考网络索引(=1)
  nPermutations = 200,                 # 置换次数(越多越准,但越慢)
  randomSeed = 42,                     # 随机种子
  networkType = "signed",              # 网络类型
  verbose = 3
)

# 提取保存性统计量
stats <- mp$preservation$Z$ref.Test     # Z统计量
# Zsummary > 10: 强保存
# 2 < Zsummary < 10: 中等保存
# Zsummary < 2: 不保存

# 可视化
moduleSize <- stats[, "moduleSize"]
Zsummary <- stats[, "Zsummary.pres"]

plot(moduleSize, Zsummary,
     xlab="Module Size", ylab="Zsummary Preservation",
     main="Module Preservation", pch=19, col="blue")
abline(h=10, col="red", lty=2)   # 强保存线
abline(h=2, col="darkgreen", lty=2)  # 弱保存线
text(moduleSize, Zsummary, labels=rownames(stats), pos=3, cex=0.7)
legend("bottomright", c("Z>10: Strong", "Z>2: Moderate", "Z<2: Weak"),
       col=c("red","darkgreen","gray"), lty=2)

四、模块-表型关联

# ===== Module-Trait关系分析 =====
# 读取临床/表型数据
traits <- read.csv("clinical_traits.csv", row.names=1)
# 列:age, gender, tumor_stage, survival_status, treatment_response

# 计算模块特征基因(ME)
MEs <- moduleEigengenes(datExpr, mergedColors)$eigengenes
MEs <- orderMEs(MEs)  # 排序

# 计算模块-表型相关性
moduleTraitCor <- cor(MEs, traits, use="p")          # Pearson相关
moduleTraitPvalue <- corPvalueStudent(moduleTraitCor, nrow(datExpr))  # p值

# 热图可视化
textMatrix <- paste(
  signif(moduleTraitCor, 2), "\n(",
  signif(moduleTraitPvalue, 1), ")", sep=""
)
dim(textMatrix) <- dim(moduleTraitCor)

labeledHeatmap(
  Matrix = moduleTraitCor,
  xLabels = colnames(traits),
  yLabels = names(MEs),
  ySymbols = names(MEs),
  colorLabels = FALSE,
  colors = blueWhiteRed(50),
  textMatrix = textMatrix,
  setStdMargins = FALSE,
  cex.text = 0.5,
  main = "Module-Trait Relationships (Signed Network)"
)

# ===== Hub基因鉴定 =====
# kME = 基因与模块特征基因的相关性
# kME越高 → 基因对模块越重要(hub基因)

kME <- signedKME(datExpr, MEs, corFnc="bicor")  # 计算kME

# 找蓝色模块的hub基因
blue_genes <- colnames(datExpr)[mergedColors == "blue"]
blue_kME <- kME[blue_genes, "kMEblue"]
hub_genes <- names(sort(blue_kME, decreasing=TRUE))[1:20]  # Top 20 hub
cat("Blue module hub genes:\n", hub_genes, "\n")

五、常见报错与解决

报错信息原因解决方案
pickSoftThreshold: R²<0.8数据不满足scale-free增大power范围(至20)或检查数据
blockwiseModules: memory基因太多减小maxBlockSize或减少基因数
Only grey module基因间相关性太低降低minModuleSize或增加样本数
Zsummary negative模块不保存正常结果,说明模块无跨数据集意义
bicor warning数据中有常数列过滤方差为0的基因
signed vs unsigned不同方法差异signed更合理(推荐)

六、面试高频问题

Q1: 为什么推荐signed network?

A: Unsigned把正相关和负相关的基因放一起(只看绝对值),生物学上不合理。Signed只把正相关的基因聚成模块,负相关的在不同模块。例如:激活型基因和抑制型基因不应在同一模块。WGCNA开发者明确推荐signed network。

Q2: 模块保存性检验有什么用?

A: 验证在数据集A中发现的模块是否在数据集B中也存在。Zsummary>10说明模块稳健,有跨数据集的生物学意义;Zsummary<2说明模块可能是数据集特异的噪声。这在发现疾病biomarker模块时非常重要——只有保存的模块才可能有普遍的生物学意义。

Q3: 如何选择hub基因?

A: Hub基因选择标准:①kME值高(>0.8):与模块特征基因强相关;②模块内连接度高:与模块内其他基因广泛相关;③基因显著性(GS)高:与感兴趣的表型强相关;④文献支持:已知与该生物学过程相关。最佳候选是同时满足高kME和高GS的基因。


七、速查表

# ===== WGCNA进阶速查 =====

# Signed网络构建
sft <- pickSoftThreshold(datExpr, networkType="signed", corFnc="bicor")
net <- blockwiseModules(datExpr, power=sft$powerEstimate,
    networkType="signed", corType="bicor", TOMType="signed",
    minModuleSize=30, mergeCutHeight=0.25)

# 模块保存性
mp <- modulePreservation(multiData, multiColor,
    referenceNetworks=1, nPermutations=200)
# Zsummary > 10: 强保存
# 2-10: 中等  | < 2: 不保存

# 模块-表型关联
moduleTraitCor <- cor(MEs, traits, use="p")

# Hub基因
kME <- signedKME(datExpr, MEs, corFnc="bicor")
hub <- names(sort(kME$kMEblue, decreasing=TRUE))[1:20]

# 关键参数选择:
# networkType = "signed" (推荐)
# corType = "bicor" (稳健)
# minModuleSize = 30 (经验值)
# mergeCutHeight = 0.25 (默认)
# power: signed通常10-14, unsigned通常6-12