ARTICLE DETAIL

资讯详情

深耕网站视觉设计与运营推广的一线实战洞察。

R语言微生物α多样性分析全流程:从OTU表到组间比较

R语言微生物α多样性分析全流程:从OTU表到组间比较 简介一份面向微生物群落生态研究者的R语言α多样性分析项目代码尤其适合生信入门者与农业资源环境等领域的学生。压缩包共10个文件以R脚本、txt数据与结果、md说明文档为主整体仅16KB轻量易读。核心脚本实现数据加载、Sobs/Chao/ACE丰富度指数与Shannon/Simpson多样性指数的批量计算并通过箱线图直观展示不同组别Shannon指数分布便于比较样本间多样性差异。另附md文档对分析流程和输出结果作解读配套txt数据文件可快速替换为自己的OTU/丰度表进行复现。目前已有227人学习下载适合需要快速掌握α多样性指数计算、可视化作图及结果阐述的研究者参考。 上个月一个做环境微生物的朋友给我发来一张OTU表问我说能不能帮我把每个样本的Shannon指数算出来再比较一下两组之间有没有显著差异这种需求在微生物组学研究里太常见了。拿到16S或者宏基因组测序下机数据、经过质控和聚类之后手头就是一张丰度表而后续最基础也最关键的一步就是用R把α多样性分析做完整、做规范。今天这篇就把我自己目前最常用的一套R分析流程完整整理出来从数据导入、指数计算、稀释曲线到组间差异检验全部给出可以直接复现的代码和操作要点适合正在用R做微生物多样性的初学者也适合想把自己的分析流程规范化、成套化的老手。1. α多样性到底在算啥指数选型决定了你讲故事的方向1.1 一个群落里“丰富”和“均匀”是两回事α多样性的字面意思是“单个样本内部的物种多样性”。它回答的问题非常朴素这个样本里有多少种微生物这些微生物的丰度分布是均匀的还是被少数优势种垄断很多人习惯性地把所有α多样性指数一次性算出来然后看哪个显著就写哪个。这种思路其实风险很大。Observed species、Chao1、ACE这类指数衡量的是群落的“物种丰富度”说白了就是数数——检测到了多少个OTU/ASV或者估算还有多少个没被采到的物种。Shannon和Simpson则更关注“均匀度”它不仅要看物种数量还要看每个物种的相对丰度分布。一个只有两种微生物的样本如果两种各占一半Shannon指数反而可能比一个含有十种但其中九种都只占0.1%的样本更高。我习惯用一个生活化的类比来解释这件事考察两个城市的美食多样性。城市A有100家餐厅但其中95家都是同一家连锁火锅城市B只有30家餐厅但川菜、粤菜、日料、西餐各占一部分。如果你只看“餐厅种类数量”城市A的物种丰富度更高但如果你关心“吃东西的选择权是否被垄断”城市B的均匀度明显更好。微生物群落分析也是一样指数怎么选取决于你想回答什么科学问题。1.2 Observed、Chao1、Shannon、Simpson怎么选实操中我默认会同时计算Observed、Chao1、Shannon和Simpson四个指数然后根据数据特点和研究目的决定以哪个为核心指标Observed最直观的观测物种数适合先快速看一眼样本间的大致差异。Chao1基于稀有物种singleton和doubleton估算的物种总数。如果测序深度不够Chao1比Observed更能反映群落真实的物种潜在规模。Shannon对物种丰度和均匀度都敏感对稀有物种也有一定的权重是目前文献里引用最普遍的指数。Simpson对优势物种非常敏感本质上回答的是“随机抽取两个个体它俩属于同一物种的概率”。如果样本里有明显的优势菌群Simpson对群落结构变化的反应比Shannon更敏锐。所以我的建议是把四类指数都算出来放在补充材料里正文中挑一两个最能支撑研究假设的展开分析。例如关注肠道菌群失调Simpson往往更贴合“优势菌是否过度膨胀”这个问题而关注环境梯度对物种多样性的影响Shannon和Chao1的组合会更稳健。这就是我常说的一句话指数本身没有好坏只有“适不适合你正在讲的故事”。2. 开工前先解决两件麻烦事R环境与数据格式2.1 phyloseq为什么难装怎么一次装好R语言做微生物组学分析绕不开的核心包是phyloseq。它把OTU丰度表、样本元数据、分类注释表和系统发育树封装在一个统一的对象里后续的α多样性、β多样性、差异丰度分析全都基于这个对象操作。但phyloseq的安装对新手而言是第一个劝退点——它不在CRAN上需要从Bioconductor安装而且依赖关系复杂经常报错。我自己现在标准的安装流程是这样的# 先装BiocManager install.packages(BiocManager) # 再通过BiocManager安装phyloseq BiocManager::install(phyloseq) # 同时把可视化相关的包也装上 install.packages(c(tidyverse, vegan, ggplot2, ggpubr, iNEXT))如果你在安装phyloseq的过程中看到类似“package ‘phyloseq’ is not available for this version of R”“had non-zero exit status”“there is no package called ‘X’”这类提示通常不是phyloseq本身的问题而是它的某个依赖包没装上或者R版本和Bioconductor版本不匹配。这时候不要反复硬装先看报错信息里提示缺的包是哪一个单独把它装好再回头装phyloseq。这里有一个细节值得强调Windows用户如果安装R包时报错信息里出现“warning: rtools is required to build r packages but is not currently installed”说明系统里缺少Rtools。这个工具相当于Windows环境下的C语言编译套件很多从源码安装的R包都需要借助它编译。你需要去R官网的“Rtools”页面下载对应你R版本的安装包装好之后重启RStudio再执行安装命令就顺畅多了。2.2 OTU表、元数据、分类表的格式规范环境准备好之后最花时间的其实是数据整理。我见过太多人在这一步被卡住原因就是表格格式不符合phyloseq的读取要求。我们需要准备的核心数据是两部分丰度表和样本元数据。丰度表要求行为OTU/ASV第一列是ID列为样本名元数据要求行为样本名列为分组、时间、临床信息等变量。两者的样本名必须完全一致名称里尽量不要带空格、减号、括号等特殊符号建议统一用“字母数字”的组合例如“CK1”“Treat2”。这能避免后续百分之八十的“莫名其妙找不到样本”问题。读取和构建的代码如下library(phyloseq) library(tidyverse) # 读取OTU/ASV丰度表 otu - read.table(otu_table.txt, header TRUE, row.names 1, sep \t, check.names FALSE) # 读取样本元数据 meta - read.table(metadata.txt, header TRUE, row.names 1, sep \t, check.names FALSE) # 转换为phyloseq需要的格式 OTU - otu_table(as.matrix(otu), taxa_are_rows TRUE) META - sample_data(meta) # 合并成phyloseq对象 ps - phyloseq(OTU, META)注意代码中的check.names FALSE非常关键。如果不加R会自动把列名里的“-”“空格”等非法字符替换成点号导致元数据里的样本名和丰度表里的样本名对不上分析时大量样本被静默丢弃。如果你手头还有分类注释表比如Greengenes或SILVA的注释结果也可以用tax_table()函数把它合并进phyloseq对象做后续的门水平堆叠图等分析。但纯做α多样性的话species这一部分可以暂时不用。3. 核心代码从OTU表到多样性指数和稀释曲线3.1 数据读入与phyloseq对象构建前面已经完成了phyloseq对象的构建接下来我会统一采用ps这个变量名来操作所有后续分析。在实际项目中我一般会在分析前先做一次“体检”确认数据读进来没有问题# 查看样本数量和OTU数量 sample_names(ps) # 样本名 ntaxa(ps) # OTU/ASV数量 # 查看元数据信息 sample_data(ps)如果读入的样本数和你元数据里的行数一致就可以继续往下走了。如果少了请立刻检查样本名是否匹配、是否有空行或重复行。我发现很多人喜欢在这里偷懒不复检结果后面画出来的图里样本数少了好几个还得回头重新来一遍浪费的时间比一开始认真核对多得多。3.2 多样性指数批量计算与结果导出phyloseq内置了estimate_richness()函数可以一次性计算多数常用α多样性指数。但一个容易踩的坑是默认返回的列里同时包含Observed、Chao1、ACE、Shannon、Simpson、InvSimpson等其中有些指数你未必用得上。为了后续合并分组信息方便我会先提取需要的几个然后手动把样本名变成一列再连上元数据# 计算α多样性指数 alpha - estimate_richness(ps, measures c(Observed, Chao1, Shannon, Simpson)) # 把样本名转为显式列方便后续join alpha - rownames_to_column(alpha, var SampleID) # 从元数据中提取分组信息 group_info - meta %% rownames_to_column(var SampleID) %% select(SampleID, Group) # 合并分组 alpha - left_join(alpha, group_info, by SampleID) # 导出CSV write.csv(alpha, alpha_diversity.csv, row.names FALSE)这段代码执行完后你会得到一张包含每个样本各指数数值和分组信息的表格。这张表本身就可以作为论文的补充材料提交也是后续做图和统计检验的数据基础。导出之后我习惯先打开CSV瞄一眼确认分组列没有变成NA。这里还有一个容易忽略的细节如果数据量特别大、某些样本测序深度很低estimate_richness()可能会对某些指数返回NA。不要直接删掉这些样本先检查是不是测序深度不足导致的。如果只是因为深度差异太大下一步要考虑抽平处理。3.3 稀释曲线的两种做法稀释曲线rarefaction curve是α多样性分析里最经典的“预检图”。它的作用是验证一个问题当前的测序深度是否足够捕获这个群落大部分的物种。曲线的横轴是测序量样本序列条数纵轴是观测到的物种数量。如果曲线末端趋于平缓说明测序深度基本饱和如果仍然陡峭上升说明继续加大测序量很可能还会发现更多物种。我用得最多的实现方法是vegan包里的rarecurve()它对phyloseq对象不直接支持所以我会先把丰度表转成矩阵再画library(vegan) # 提取丰度矩阵行是OTU列是样本 otu_mat - as.data.frame(as.matrix(otu_table(ps))) # 转置为vegan需要的格式行是样本列是OTU otu_mat_t - t(otu_mat) # 画稀释曲线 rarecurve(otu_mat_t, step 100, lwd 2, col rainbow(nrow(otu_mat_t)), xlab Number of sequences, ylab Observed OTUs) # 添加图例 legend(bottomright, legend rownames(otu_mat_t), col rainbow(nrow(otu_mat_t)), lty 1, lwd 2, cex 0.6, ncol 2)但说实话rarecurve()画出来的原始图需要手动调整配色和图例做初稿可以做最终发表图不算理想。更推荐的替代方案是iNEXT包它能用插值和外推两种方式同时估计物种多样性对未来的测序投入也有预测价值。如果你只需要一张简单、可以直接放进报告里的稀释曲线我建议用ggplot2对rarecurve()的输出做二次加工把每条样本曲线替换成按分组合并的曲线带。无论用哪种方案稀释曲线最好放在正文或补充材料里。审稿人看到平滑的曲线时会默认你的数据支持后续的多样性比较这个“第一印象分”还是值得花十分钟拿到的。4. 组间差异检验与出版级图表的细节处理4.1 为什么默认用Wilcoxon/Kruskal-Wallis而不是t检验计算完指数接下来通常要做组间比较比如疾病组和健康组相比Shannon指数是否显著降低。很多新手会习惯性地用t检验但这个做法在微生物数据里并不稳健。α多样性指数往往不服从正态分布尤其是样本量小、组内波动大的时候t检验的前提条件很难满足。我的默认策略是两组比较用Wilcoxon秩和检验也叫Mann-Whitney U检验多组比较用Kruskal-Wallis检验。这两个都是非参数检验不依赖正态分布假设。如果显著性结果与科学问题高度相关再追加排列检验或ANOVA作为稳健性验证都来得及。两组比较的代码# 以Shannon为例比较Group A和Group B wilcox.test(Shannon ~ Group, data alpha, subset Group %in% c(A, B))多组比较的代码kruskal.test(Shannon ~ Group, data alpha)要注意多组比较的Kruskal-Wallis检验只告诉你“至少有一组与其它组不同”但具体是哪几对有差异还需要做两两比较。这里涉及到多重比较校正问题如果你有5组两两组合就有10次检验每次检验的显著性水平都是0.05的话假阳性概率会大幅升高。我通常用pairwise.wilcox.test()并设置p.adjust.method BHBenjamini-Hochberg方法来控制错误发现率pairwise.wilcox.test(alpha$Shannon, alpha$Group, p.adjust.method BH)我见过很多已发表的论文只给出一组Kruskal-Wallis的p值然后就说“组间存在显著差异”不给具体哪两组差异。这种写法在规范性要求高的期刊里很容易被审稿人挑刺。所以只要组别数量大于2两两比较和多重校正这一步不要省略。4.2 指数合并为长数据后的分面箱线图α多样性分析出图时最常见的做法是把多个指数并排展示。但这里有个常见问题estimate_richness()返回的宽格式数据框每种指数是一列不适合直接用ggplot2分面。所以我的习惯是先把数据从宽格式转成长格式再用ggplot2绘制分面箱线图叠加散点。长格式转换和作图的代码library(tidyr) library(ggplot2) # 选择需要的列转换为长格式 alpha_long - alpha %% select(SampleID, Group, Observed, Chao1, Shannon, Simpson) %% pivot_longer(cols c(Observed, Chao1, Shannon, Simpson), names_to Index, values_to Value) # 分面箱线图并叠加散点 p - ggplot(alpha_long, aes(x Group, y Value, fill Group)) geom_boxplot(outlier.shape NA, alpha 0.7, width 0.6) geom_jitter(width 0.15, size 1.5, alpha 0.5) facet_wrap(~ Index, scales free_y, ncol 2) theme_bw(base_size 14) theme(legend.position none, axis.text.x element_text(angle 45, hjust 1)) labs(x NULL, y Alpha diversity index) ggsave(alpha_diversity_boxplot.pdf, p, width 8, height 6)这里使用的scales free_y非常关键。因为Observed和Chao1的数值范围可能是几百到几千而Shannon和Simpson的范围可能只有0到5如果共用一个纵轴数值小的指数会被压成一条线什么都看不清。用自由纵轴分面后每个子图都能完整展示自己的数据分布。4.3 显著性标记与多重比较校正在图中标注显著性时我一般会先用stat_compare_means()做快速标记但更严谨的做法是手动把前面pairwise.wilcox.test()算出的p值整理好再映射到图上。不要直接在图里调用统计检验因为多个指数分面之后每个面板都会重复跑一遍检验等你想要调整检验参数时反而麻烦。一种推荐做法是先在一个表格里把四个指数的比较结果全部算好再按需添加p值。例如# 计算各指数的组间p值 p_list - alpha_long %% group_by(Index) %% summarise(p_value wilcox.test(Value ~ Group, data cur_data())$p.value) %% mutate(label ifelse(p_value 0.001, ***, ifelse(p_value 0.01, **, ifelse(p_value 0.05, *, ns)))) print(p_list)然后把p_list中的label传递到图上用geom_text()添加显著性标记。这种“先计算后绘图”的思路能保证你最终呈现在图上的数字和你在正文里报告的数字完全一致不会出现图上是0.049、文字里却是0.048这类让审稿人皱眉的细节偏差。5. 这一路我没少踩坑环境配置与结果解读问题5.1 rtools缺失和BiocManager版本不对前面提过rtools的问题但我还想再展开一次。很多人遇到的报错信息是“warning: rtools is required to build r packages but is not currently installed”这通常发生在安装某个依赖Rcpp、RcppEigen这类需要编译的包时。如果你只是用RStudio自带的“Install Packages”按钮安装弹出来的警告很容易被忽略然后安装进程失败你还没明白发生了什么。我的建议是Windows用户在第一轮安装包之前直接去下载安装与当前R版本匹配的Rtools一次性把编译环境准备好。装了Rtools之后如果还出现“no known arch”或“cannot find C compiler”这类提示请先关闭并重启RStudio让R重启后重新读取PATH环境变量。重启后一般就正常了。Bioconductor版本不匹配是另一个高频坑。如果你R是3.6版却用最新版BiocManager去装为R4.3设计的phyloseq报错几乎是必然的。BiocManager的好处是它会根据当前R版本自动选择匹配的Bioconductor版本所以安装phyloseq时一定要走BiocManager::install(phyloseq)而不是用install.packages()去CRAN碰运气。5.2 抽平选择不当导致样本被丢掉做稀释曲线或者计算多样性指数之前很多人会直接对整个OTU表做抽平rarefaction。vegan包里的rrarefy()函数可以把每个样本的序列数统一抽到某个深度但这里有个风险如果你的最低测序深度样本只有5000条序列而你想把深度抽到30000条那么这个样本会被直接丢弃。如果丢弃之后组内样本数量不足后续统计检验的把握度会大打折扣。所以我在做抽平之前先用min(colSums(otu))查看一下所有样本的最低测序量再来决定抽平深度。如果不同组的测序深度整体差异过大我倾向于先不抽平而是用相对丰度标准化后的数据计算多样性指数或者用iNEXT包直接对不同测序深度进行数学外推。现在的期刊也越来越接受“不抽平、用统计分析校正测序深度差异”的处理方式。另外抽平会引入随机性同样的数据分析两次结果会有细微差别。正式分析前记得设置随机数种子set.seed(123)保证结果可重复。5.3 因子顺序和图例乱序这可能是最不起眼但最影响图表质量的问题。当你把Group列当作分组变量时ggplot默认会按字母顺序排列箱线图比如“Group”“Healthy”“Treat”的顺序可能完全不符合你想要的“先对照、后处理”的逻辑。如果不调整图上的顺序和正文段落的叙述顺序对不上读者看起来就会觉得别扭。解决办法是在画图前手动把因子水平设置好alpha$Group - factor(alpha$Group, levels c(Control, Treat))levels的顺序就是你箱线图从左到右的顺序。这一步看起来简单很多人忽略等到图发给合作者后对方要求“能不能把Control放前面、Treat放后面”时又要重新跑一遍分析和导图。先设置好因子顺序能免掉后续很多来回沟通的麻烦。还有一个常见问题是图例文字出现中文乱码。R的默认字体对中文支持不好Windows下尤其突出。我的一般做法是图里的样本名、分组名、轴标题全用英文最终报告需要中文说明时用AI或排版软件后期添加。这样能彻底避开R图形设备的中文显示问题。5.4 我的个人体会跑了几年微生物数据之后我最大的体会是α多样性分析只是整个“微生物组故事”的第一块拼图它本身并不能证明机制但它决定了你后续分析的方向是否可信。一个连α多样性指数和分组变量都对不齐、稀释曲线乱成一团的数据集后面无论做多少个β多样性排序、LEfSe分析都很难让审稿人放心。所以我在每个新项目里都会强制自己先跑一遍这套流程读入数据、检查样本名、计算四个核心指数、画稀释曲线、做组间检验、保存所有中间结果。这不需要太久却能让后续每一步分析都站在一个干净、可复现的基础上。希望这份流程也能帮你少走一点弯路把时间花在真正值得深挖的科学问题上。最后再分享一个很小的技巧把你最常用的α多样性分析代码封装成一个R脚本每次新项目只需要改文件路径和分组列名其他代码原样复用。时间久了这个脚本会慢慢变成你自己顺手的数据分析工具比任何“一键分析平台”都更可靠。这也是我从一开始不用图形界面点来点去坚持用脚本驱动分析的原因——数据和代码分离每一张图都经得起溯源和复现。本文还有配套的精品资源点击获取
返回列表