跳转至

175_微生物组Beta多样性可视化

一句话概述

Beta多样性衡量不同样本之间微生物群落组成的差异,通过距离矩阵和降维可视化(PCoA/NMDS)将多维群落差异映射到二维空间,是微生物组研究中比较不同处理/环境群落结构差异的核心方法。

核心知识点表格

知识点说明
Beta多样性定义样本间群落组成差异的度量
常用距离Bray-Curtis(丰度)、UniFrac(系统发育)、Jaccard(存在/缺失)
Weighted UniFrac考虑丰度的系统发育距离,对优势物种敏感
Unweighted UniFrac仅考虑存在与否的系统发育距离,对稀有物种敏感
PCoA主坐标分析,保持样本间距离关系的线性降维
NMDS非度量多维缩放,基于排序保持距离的非线性降维
PERMANOVA置换多元方差分析(adonis2),检验分组是否显著
betadisper检验组间方差齐性,PERMANOVA的前提假设检验

步骤详解

第一步:理解Beta多样性距离

白话解释:把每个样本想象成空间中的一个点,样本间微生物组成越相似,点之间的距离就越近。Beta多样性分析就是计算这些"距离",然后用图形展示出来。

技术细节:不同距离度量关注的生态学信息不同。Bray-Curtis是最常用的生态距离,考虑物种的相对丰度差异;Jaccard只看物种有没有,不看多少;UniFrac还加入了物种间的进化关系。

library(vegan)
library(phyloseq)

# 模拟一个OTU表(行=样本,列=OTU)
set.seed(42)
otu_table <- matrix(rpois(500, lambda = 10), nrow = 20, ncol = 25)
rownames(otu_table) <- paste0("Sample", 1:20)
colnames(otu_table) <- paste0("OTU", 1:25)

# 计算不同距离矩阵
dist_bray <- vegdist(otu_table, method = "bray")      # Bray-Curtis
dist_jaccard <- vegdist(otu_table, method = "jaccard")  # Jaccard
dist_euclidean <- vegdist(otu_table, method = "euclidean") # Euclidean(不推荐直接用)

# 如果有phyloseq对象,可以计算UniFrac
# dist_unifrac <- UniFrac(physeq, weighted = TRUE)
# dist_uunifrac <- UniFrac(physeq, weighted = FALSE)

第二步:PCoA降维可视化

白话解释:距离矩阵是一个n×n的大表,没法直接看。PCoA把这个表"压缩"到二维或三维的图上,让我们能直观地看到哪些样本组成相似(距离近)或不同(距离远)。

技术细节:PCoA(Principal Coordinates Analysis)是对距离矩阵进行特征分解,找到能最大程度保留原始距离信息的低维坐标。每个轴的解释方差百分比反映了该维度捕获的信息量。

library(ape)
library(ggplot2)

# 元数据
metadata <- data.frame(
  Sample = paste0("Sample", 1:20),
  Group = rep(c("Control", "Treatment"), each = 10),
  Timepoint = rep(c("T1", "T2"), 10)
)

# PCoA分析
pcoa_result <- pcoa(dist_bray)

# 提取坐标和解释方差
pcoa_df <- data.frame(
  PC1 = pcoa_result$vectors[, 1],
  PC2 = pcoa_result$vectors[, 2],
  Group = metadata$Group,
  Timepoint = metadata$Timepoint
)

var_explained <- round(pcoa_result$values$Relative_eig[1:2] * 100, 1)

# 绘制PCoA图
ggplot(pcoa_df, aes(x = PC1, y = PC2, color = Group, shape = Timepoint)) +
  geom_point(size = 3, alpha = 0.8) +
  stat_ellipse(aes(group = Group), level = 0.95, linetype = "dashed") +
  labs(
    x = paste0("PCoA1 (", var_explained[1], "%)"),
    y = paste0("PCoA2 (", var_explained[2], "%)"),
    title = "Beta Diversity (Bray-Curtis)"
  ) +
  theme_minimal() +
  theme(legend.position = "right")

第三步:NMDS降维可视化

白话解释:NMDS是另一种降维方法,它不像PCoA那样追求精确保留距离值,而是保持样本间距离的"排名顺序"。有时候NMDS能比PCoA更好地展示复杂的群落模式。

技术细节:NMDS通过迭代优化将样本映射到低维空间,使得低维空间中的距离排序尽可能接近原始距离排序。stress值衡量拟合质量:<0.05表示极好,<0.1表示好,<0.2表示可接受,>0.2表示较差。

# NMDS分析
set.seed(123)
nmds_result <- metaMDS(otu_table, distance = "bray", k = 2, trymax = 100)

# 查看stress值
cat("Stress:", nmds_result$stress, "\n")

# 提取坐标
nmds_df <- data.frame(
  NMDS1 = nmds_result$points[, 1],
  NMDS2 = nmds_result$points[, 2],
  Group = metadata$Group
)

# 绘制NMDS图
ggplot(nmds_df, aes(x = NMDS1, y = NMDS2, color = Group)) +
  geom_point(size = 3) +
  stat_ellipse(level = 0.95) +
  annotate("text", x = Inf, y = Inf,
           label = paste("Stress =", round(nmds_result$stress, 3)),
           hjust = 1.1, vjust = 1.5, size = 4) +
  theme_bw() +
  labs(title = "NMDS (Bray-Curtis)")

第四步:统计检验(PERMANOVA)

白话解释:光看图还不够,我们需要统计检验来判断分组之间的差异是否"真实"而非随机。PERMANOVA就是专门用于此的置换检验方法。

技术细节:PERMANOVA(adonis2)将距离矩阵的总变异分解为组间和组内部分,通过置换检验计算p值。R²值表示分组因素解释的变异比例。注意PERMANOVA假设组间方差齐性,需用betadisper先检验。

# PERMANOVA检验
set.seed(999)
adonis_result <- adonis2(dist_bray ~ Group * Timepoint, data = metadata, permutations = 999)
print(adonis_result)

# 方差齐性检验
bd <- betadisper(dist_bray, metadata$Group)
permutest(bd, pairwise = TRUE)
# p > 0.05 表示方差齐性,PERMANOVA结果可靠

# 多组成对比较(如果有>2组)
library(pairwiseAdonis)
pairwise.adonis(dist_bray, metadata$Group, p.adjust.m = "BH")

# ANOSIM检验(替代方法)
anosim_result <- anosim(dist_bray, metadata$Group, permutations = 999)
summary(anosim_result)

第五步:使用phyloseq进行整合分析

library(phyloseq)

# 创建phyloseq对象
OTU <- otu_table(otu_table, taxa_are_rows = FALSE)
META <- sample_data(metadata)
rownames(META) <- metadata$Sample
physeq <- phyloseq(OTU, META)

# phyloseq内置的排序方法
ord_pcoa <- ordinate(physeq, method = "PCoA", distance = "bray")
ord_nmds <- ordinate(physeq, method = "NMDS", distance = "bray")

# 使用plot_ordination
p <- plot_ordination(physeq, ord_pcoa, color = "Group", shape = "Timepoint") +
  geom_point(size = 3) +
  stat_ellipse(aes(group = Group)) +
  theme_minimal() +
  ggtitle("PCoA - Bray-Curtis")
print(p)

第六步:Python实现(scikit-bio + matplotlib)

import numpy as np
import pandas as pd
from skbio import DistanceMatrix
from skbio.stats.ordination import pcoa
from skbio.stats.distance import permanova
from scipy.spatial.distance import braycurtis, pdist, squareform
import matplotlib.pyplot as plt

# 计算Bray-Curtis距离矩阵
otu = np.random.poisson(10, (20, 25))
sample_ids = [f"Sample{i}" for i in range(1, 21)]
bc_distances = squareform(pdist(otu, metric='braycurtis'))
dm = DistanceMatrix(bc_distances, ids=sample_ids)

# PCoA
pcoa_result = pcoa(dm)
pcoa_df = pcoa_result.samples[['PC1', 'PC2']]
pcoa_df['Group'] = ['Control']*10 + ['Treatment']*10

# 可视化
fig, ax = plt.subplots(figsize=(8, 6))
for group, color in [('Control', 'blue'), ('Treatment', 'red')]:
    mask = pcoa_df['Group'] == group
    ax.scatter(pcoa_df.loc[mask, 'PC1'], pcoa_df.loc[mask, 'PC2'],
               c=color, label=group, s=60, alpha=0.7)
ax.set_xlabel(f"PC1 ({pcoa_result.proportion_explained[0]*100:.1f}%)")
ax.set_ylabel(f"PC2 ({pcoa_result.proportion_explained[1]*100:.1f}%)")
ax.legend()
ax.set_title("PCoA (Bray-Curtis)")
plt.tight_layout()
plt.savefig("beta_diversity_pcoa.png", dpi=300)

# PERMANOVA
grouping = pd.Series(['Control']*10 + ['Treatment']*10, index=sample_ids)
result = permanova(dm, grouping, permutations=999)
print(result)

实战命令速查

# QIIME2中的Beta多样性
# qiime diversity beta --i-table table.qza --p-metric braycurtis --o-distance-matrix bray.qza
# qiime diversity pcoa --i-distance-matrix bray.qza --o-pcoa pcoa.qza
# qiime emperor plot --i-pcoa pcoa.qza --m-metadata-file meta.tsv --o-visualization emperor.qzv

# R一行完成PCoA+可视化
library(microeco); library(magrittr)
# dataset$cal_betadiv(unifrac = FALSE) %>% dataset$plot_betadiv()

# 快速计算多种距离
lapply(c("bray","jaccard","horn","morisita"), function(m) vegdist(otu_table, method = m))

面试常问点

Q1: Bray-Curtis和UniFrac距离的区别是什么? A: Bray-Curtis基于物种丰度计算差异,不考虑物种间的进化关系。UniFrac结合系统发育树信息,亲缘关系近的物种差异被降低权重。如果两个样本有不同物种但这些物种亲缘关系很近,UniFrac距离会小,Bray-Curtis距离可能较大。

Q2: PCoA和NMDS如何选择? A: PCoA是线性方法,计算快速确定性,适合大多数情况。NMDS是非线性方法,对复杂的非线性关系表现更好,但需要迭代且结果可能不唯一。实际中建议两者都做,结果一致则更可靠。

Q3: PERMANOVA的R²值如何解读? A: R²表示分组因素解释的总变异比例。例如R²=0.15表示分组解释了15%的群落变异。微生物组研究中R²通常在0.05-0.30之间。R²小但p值显著说明存在真实但较小的差异。

Q4: PERMANOVA显著但PCoA图上看不出分离怎么办? A: 这通常是因为组间差异虽然统计显著但效应量小,或者差异主要在PCoA未展示的高阶轴上。可以查看PCoA的第3、4轴,或使用dbRDA约束排序方法直接展示分组相关的变异。

Q5: 为什么不直接用PCA分析微生物组数据? A: PCA假设变量间呈线性关系,使用欧氏距离,不适合物种丰度数据(含大量零值、高度偏态)。PCoA可以使用生态距离,NMDS可以处理非线性关系,都比PCA更适合微生物组数据。

Q6: betadisper检验不通过怎么办? A: betadisper不通过意味着组间方差不齐,PERMANOVA的p值可能被膨胀。可以报告betadisper结果作为补充,或使用其他方法如ANOSIM(对方差齐性假设更宽松)。

易错点

  1. 忘记数据标准化:直接用原始counts计算Bray-Curtis会被测序深度主导,应先做相对丰度或rarefaction
  2. PCoA负特征值:某些距离(如UniFrac)可能产生负特征值,需用correction参数校正
  3. NMDS的stress值过高:stress>0.2时应增加维度(k=3),或检查数据质量
  4. PERMANOVA嵌套设计遗漏:纵向数据需在PERMANOVA中指定strata参数控制重复测量
  5. 椭圆图的误解:PCoA图上的椭圆是95%置信椭圆,不代表统计显著性

补充知识

距离度量选择指南

距离适用场景特点
Bray-Curtis通用,最常用考虑丰度,0-1范围
Jaccard关注物种组成仅考虑有/无
Weighted UniFrac关注优势物种的系统发育差异需要进化树
Unweighted UniFrac关注稀有物种的系统发育差异需要进化树
Aitchison组成型数据基于CLR变换+欧氏距离

约束排序方法

当想直接展示环境因子对群落的影响时,可以使用约束排序方法(如db-RDA):

# db-RDA(基于距离的冗余分析)
dbrda_result <- dbrda(dist_bray ~ Group + Timepoint, data = metadata)
anova(dbrda_result, by = "terms")  # 检验各因子显著性
plot(dbrda_result)