ARTICLE DETAIL

资讯详情

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

16S扩增子属水平分析全流程:从质控到差异检验的实战指南

16S扩增子属水平分析全流程:从质控到差异检验的实战指南 做微生物组研究的朋友大概都有同感16S扩增子数据拿到手之后最容易被合作方、审稿人追问的其实不是OTU/ASV有多少而是“你这几个组之间到底有哪些属genus变了”。属这个层级卡在门和种之间上可以概括群落结构下又比种更经得起16S单区域测序的精度考验。我这次整理genus综合流程就是想解决一个具体问题从Illumina下机的双端序列开始怎么稳定、可复现地走到一张可信的属水平丰度表再顺顺利利做完下游的多样性、差异分析和可视化。整套流程我自己跑了不下十批数据中间踩过不少坑这里一次性说清楚。内容不追求代码逐行讲解重点讲清楚每一步为什么这么做、参数为什么这么定、哪些地方最容易出错。1. 为什么整套分析要把“属”作为出口1.1 分类学层级里属是最适合做综合的粒度很多刚接触扩增子分析的人会纠结一个问题手里有NCBI、Greengenes这么多参考数据库能不能直接注释到种我的答案是16S V3-V4区域的序列长度通常只有400多bp很多亲缘关系非常近的物种在这段序列中几乎没有差异强行注释到种很容易出现“假种名”后续解释起来非常尴尬。门和纲的问题则相反太粗了。一张群落组成堆叠图中你只能看到Proteobacteria、Firmicutes这类大板块的此消彼长但这些大板块里往往只有一两个属在真正驱动差异把功劳归给整个门会掩盖实际的生物学信号。属正好落在两者之间的甜点区。从信息量上看属水平能区分Pseudomonas和Bacillus这种常见功能类群从分类学可靠性上看绝大多数16S扩增子片段足以稳定区分到属从统计检验角度看属水平丰度矩阵的稀疏程度也适中。所以我把整套流程的出口定在“产出一份高质量属水平丰度表”再围绕它做各种下游分析。1.2 参考数据库在属水平上的现状差异属水平注释是否可靠很大程度上取决于参考数据库。目前主流有SILVA、Greengenes和GTDB三大套三者在属水平的做法差异非常大。SILVA是目前环境微生物学文献中使用最广泛的数据库最新版本到138.116S/18S覆盖度很高属名体系成熟。Greengenes 13_8曾经是QIIME时代的事实标准但已经多年不更新很多属名已经过时只适合用来跟老文献里的数据做直接比对。GTDB是近几年的新趋势它基于基因组数据重新定义了大量属分类框架更稳定但很多属名和传统命名对不上比如Bacillus被拆分成了好几个属写文章时容易跟审稿人产生“沟通成本”。我自己的习惯是环境样本优先用SILVA 138.1因为它和绝大多数己发表的生态学文献保持一致的属名体系。如果项目明确要跟老数据做meta分析我才会考虑Greengenes除非是宏基因组或高分辨率生态分型项目否则不用GTDB作为第一注释数据库。1.3 从ASV到属水平数据坍缩不是丢信息每次跑完DADA2我手里通常有几千甚至上万个ASV但注释到属级别后能真正得到可靠属名的可能只有几十到几百个。有人会觉得这一步“丢了一堆信息”其实不是。ASV是单碱基分辨率的最小分类单元属则是对它们的生物学解释层级。几千个ASV里很多是同一个属内不同菌株间的细微差异甚至是测序噪音。坍缩到属后丰度矩阵从高度稀疏变成相对稠密后续做差异检验时多重检验的罚项也会小很多。我现在做项目第一步永远是先把ASV表变成属表再从属表出发看整体格局。2. 原始数据到可信属表质控与聚类的参数细节2.1 双端序列处理先去看质量曲线再定参数拿到下机fastq我从来不会直接跑默认参数。先跑FastQC再把每张样本的序列数和质量分布列成一张汇总表。重点看R1和R2在3’端的质量衰退点这个衰退点直接决定filterAndTrim里的truncLen参数。以最常见的MiSeq 2×300测序为例R1如果从第250bp开始质量明显下滑R2从第220bp开始下滑那比较稳的参数就是truncLenc(240, 210)左右。有些人为了保留重叠区而拼命加长trunc结果把大量低质量碱基带进下游反而让错误率升高。记住一个基本原则宁可序列短一点也要质量足够硬。我通常会额外加maxEEc(2,2)这个参数代表每条序列允许的最大期望错误数设成5以上会让低质量序列混进来设成0又可能损失太多有效数据。下面是DADA2流程里我实际在用的前段参数算是基础模板library(dada2) path - data/raw fnFs - sort(list.files(path, pattern _R1.fastq.gz, full.names TRUE)) fnRs - sort(list.files(path, pattern _R2.fastq.gz, full.names TRUE)) # 去引物我习惯用 cutadapt 而不是直接在DADA2里切 # 因为 cutadapt 的错误容忍和接头处理更可控 system2(cutadapt, args c(-g, CCTACGGGNGGCWGCAG, -G, GACTACNVGGGTATCTAATCC, -o, trimmed/R1/{sample}.fastq.gz, -p, trimmed/R2/{sample}.fastq.gz, fnFs, fnRs)) errF - learnErrors(fnFs_trimmed, nbases 1e8, multithread TRUE) dadaFs - dada(fnFs_trimmed, err errF, multithread TRUE, pool pseudo)有一点值得单独提醒learnErrors这一步很多人忽略但它对整个denoise的质量影响极大。如果质量曲线显示测序十分干净nbases用默认就好如果sample不均衡需要提高nbases让错误模型学得更充分。否则后续聚类出的ASV错误率会偏高。2.2 ASV与OTU的取舍我为什么用DADA2而不是VSEARCH这一步在社区里讨论很多。DADA2输出的ASV是单碱基分辨率的真实生物学序列不再依赖97%相似度聚类所以不同批次、不同实验室的数据可以直接合并比较这是OTU做不到的。VSEARCH等聚类方法的好处是快、省内存、历史兼容性好但97%阈值本身的人为性太强。我自己的建议是新项目一律用ASV路线。因为下游不管是做系统发育树还是差异分析ASV的可解释性和可重复性都更好。只有当你明确需要跟历史上的OTU数据合并或者样本量特别大、计算资源特别紧张时才回头用VSEARCH的closed-reference策略。DADA2聚类之后一定要检查两个数字seqtab的行数和列数。行数等于有效样本数列数是总ASV数。如果总ASV数异常高比如几百个样本出几十万ASV说明前面质控偏松或者有污染如果低得离谱则可能是质控过度。这个检查耗时不到一分钟但能避免后续一路错到底。2.3 嵌合体与污染序列两个最容易被忽略的坑嵌合体是PCR过程中产生的杂合序列由两条不同模板的序列拼在一起形成。它们最麻烦的地方在于注释时往往会匹配到数据库中某个真实属造成一个并不存在的“属水平信号”。去除嵌合体是流程中不可省的步骤seqtab_nochim - removeBimeraDenovo(seqtab, method consensus, multithread TRUE)我看过一批数据去除前“注释出”了20多个差异属去除后真正显著的只剩7个。所以如果最后结果里出现大量意料之外的稀有属先回头看看嵌合体比例是否偏高。通常嵌合体占比在5%到20%之间如果超过30%说明PCR循环数可能太多或者模板质量有问题这不是软件能彻底兜住的。除了嵌合体污染问题也经常导致“假属”。我强烈建议每批实验至少带一个空白对照提取试剂空白在拿到属表后用decontam包的“frequency”或“prevalence”模式把空白对照中显著富集的属标记出来。这是我踩过最深的一个坑后面讲到结果解读时再展开。3. 注释环节决定“属名”靠不靠谱算法与数据库对比3.1 朴素贝叶斯分类器的工作原理DADA2的assignTaxonomy和QIIME2的classify-sklearn底层都是朴素贝叶斯分类器。它的核心思路是把参考序列切成长度固定的k-mer统计每个k-mer在不同分类层级的出现频次然后对每条待注释序列的所有k-mer做打分输出最可能的分类路径和对应的支持度。理解这个机制之后就会明白两个常见的坑第一k-mer无法判断序列的方向和结构所以混淆序列、前体基因片段等非目标区域序列也会被强行注释到某个属第二支持度boot值反映的是“在参考数据库中的可区分性”而不是绝对的生物学真实性。一个从未被测序的新属很可能被注释成参考库中一个相近的属名而且boot值还不低。所以我的注释策略是两轮制第一轮用assignTaxonomy设置minBoot50尽量保留候选归属跑通全流程第二轮对差异分析中出现的核心属做注释置信度审查把minBoot低于80的单独标记。这个方法会在第6部分详细展开。3.2 SILVA、Greengenes、GTDB三种数据库在属水平上的直接对比我整理了一张表方便不同项目直接对照选择数据库常用版本属水平特点适用场景主要注意事项SILVA138.1属名成熟、覆盖广多数环境样本、生态学论文原始文件大需格式化训练集Greengenes13_8属名偏旧历史OTU数据合并已停止更新新注释不推荐GTDBr220基因组驱动、属被重构宏基因组、高精度分型与传统属名差异大写文章要备注从我的经验看SILVA在属水平注释上对大多数环境样本保留率最高。Greengenes的问题不仅是“旧”而是它把很多属合并或拆分的方式跟现代分类差异太大读者会看不懂。GTDB如果要用一定要在方法部分写清楚“这里用的是GTDB分类框架”否则参考SILVA文献的同行会觉得你的Pseudomonas不是他们理解的Pseudomonas。3.3 低置信度注释的人工核查不要盲目相信一行属名每次注释完我会跑一个分布统计能有可信属名的ASV占多少比例在总丰度中占多少比例。这个数字很重要。如果序列数占比很高比如超过90%但丰度占比很低说明大多数高丰度ASV是未知类群反过来如果序列数占比不高但丰度占比很高说明主要类群注释效果不错你只需要重点关注少数核心ASV。对于重要但置信度偏低的ASV最直接的办法是取代表序列在NCBI nt库做blastn。我遇到过一个典型情况某个soil样本里大量的“unidentified Chloroplast”注释blast之后发现其实是线粒体16S序列是数据库分类层级缺陷造成的假象。把这类污染或注释偏差清理掉之后那批样本的关键差异属才真正浮出水面。4. 属水平下游分析的标准动作与统计陷阱4.1 组成谱堆叠柱状图到底怎么画才不误导拿到属水平丰度表之后最先做的事一定是看整体群落组成。我一般按属水平的平均相对丰度排序选出前20个属其余归为Others。这有两个好处一是图不会太花二是能一眼看出组间的主旋律差异。建议同时生成两套图一套是用原始reads数计算的相对丰度堆叠图另一套是经过样本间最小测序深度稀释后再计算的相对丰度。现实中很少遇到两种图完全一致的情况差异往往来自测序深度不均。如果深度差异导致主要属的相对丰度排序发生变化我会在报告里明确写出来不藏这个问题。堆叠柱状图里常见错误是有人把每个样本画成100%堆叠然后又加误差线实际上误差线这个概念在堆叠图中没有清晰统计含义。我通常只展示每个组的均值堆叠差异信息交给后面的差异属检验去呈现。4.2 α多样性与β多样性哪些用ASV表哪些用属表这是一个经常被问混淆的点。α多样性指数比如Observed、Chao1、Shannon是基于ASV表计算的因为多样性衡量的本身就是“基于单碱基分辨率的实体类群数量”如果用属表算信息损失过大多样性差异可能被抹平。β多样性则要分情况看待。Bray-Curtis距离可以直接在属水平丰度表上计算这对群落组成的整体差异很敏感也是我默认推荐的做法。UniFrac距离则必须结合系统发育树严格来说应该用ASV表建树后再计算phyloseq中的UniFrac距离。实际操作中很多工具支持把所有ASV先映射到属再在属水平算UniFrac但这样计算出来的不是真正的系统发育距离报告里写清楚即可。不管用哪种距离做组间比较时都要跑PERMANOVA也就是adonis2。这里有个非常隐蔽的坑PERMANOVA对组内离散度很敏感如果两组内部差异本身就很大即使中心点不重合也可能得到不显著的P值。所以在报告PERMANOVA结果时我必定同时跑betadisper检验β多样性离散度并注明两组是否为同质离散。4.3 差异属筛选为什么不能直接对相对丰度做t检验这是整条流程里统计陷阱最密集的地方。很多新手拿着属水平相对丰度表给每个属在两组间做个t检验或Wilcoxon检验挑出P0.05的就写进结论。问题是测序数据是组成数据每个样本所有属的相对丰度加起来等于100%一个属上升必然导致其他属相对下降这种结构性负相关会让大量“差异属”是假的。我目前常用ANCOM-BC2作为主力差异检验方法因为它显式建模了组成数据的结构性偏差。DESeq2和edgeR如果要用注意它们假设每个属的reads计数服从负二项分布适用于严格的计数数据不适合手工计算的相对丰度。LEfSe我保留用于探索性分析因为它的LDA阈值调节空间太大容易人为操纵显著性。除了检验方法我还会设两道前置过滤属至少在10%的样本中出现且至少在一个组的相对丰度均值大于0.1%。过滤后再做多重检验校正一般用BH方法控制FDR。做过这个流程的人都知道差异属从几百个缩到十几个很正常这才是可信的数量级。5. 流程工程化Snakemake串联、版本锁定与复现5.1 为什么我用Snakemake不是Nextflow当项目从一两批数据扩展到跨年度的持续采样后手工在小本本上记录命令已经完全不现实了。我用Snakemake的核心原因是它底层是Python写条件判断和动态参数非常顺手其次是它的dry-run模式能帮我在不重新计算的情况下预览整个流程的输入输出。下面是一个最简Snakefile骨架把核心步骤串起来rule all: input: results/seqtab_nochim.rds, results/taxa_silva.rds, results/barplot_top20.pdf rule dada2: input: data/raw/{sample}_R1.fastq.gz, data/raw/{sample}_R2.fastq.gz output: results/seqtab_nochim.rds script: scripts/run_dada2.R rule annotate: input: seqtabresults/seqtab_nochim.rds output: taxaresults/taxa_silva.rds script: scripts/assign_taxonomy.R rule plotbar: input: seqtabresults/seqtab_nochim.rds, taxaresults/taxa_silva.rds output: results/barplot_top20.pdf script: scripts/plot_taxa_barplot.R这个骨架的好处是一旦输入文件命名规律确定加多少个样本都只需要放到data/raw目录下Snakemake自动处理依赖关系。5.2 我踩过的三个复现坑第一个坑是数据库版本不固定。我有一次在一月份用SILVA 138注释完一批数据六月份重新拉取环境后默认下载了新版本结果同一个ASV被注释成了不同属。从那以后所有项目目录下我都会放一个database_versions.txt里面记录SILVA实际文件名和md5值。第二个坑是随机种子。降采样抽平、某些聚类算法的随机初始化都会引入不确定性。现在我在所有涉及降采样或随机抽样的脚本开头固定set.seed(123)并在输出文件名中加上随机种子号。第三个坑是依赖环境漂移。两年前写的R脚本今天用R 4.3跑可能因为dada2版本行为变化而结果不同。最稳妥的办法就是把整个分析环境做成conda环境文件environment.yml或Docker镜像锁死软件版本。虽然前期多花半小时但半年后如果有人要求复现你会感谢当时的自己。5.3 样本量不大时不值得为工程化而工程化上面这套工程化适合持续更新的项目如果你只是学生物课的几十个样本、做一次作业或初探数据直接写一个顺序执行的R脚本就够了。我自己带学生时的建议是三步以内用脚本串联三步以上且预计会反复修改参数时再上工作流引擎。流程化的目的是减少重复劳动如果流程本身比数据分析还复杂那就是本末倒置。6. 属水平结果解读我踩过的三类坑6.1 低丰度属不等于真实存在低丰度属是假阳性重灾区。生物信息中的污染主要来自两个方向一是提取试剂盒和实验室环境带来的背景菌二是测序时index hopping造成的样本间串扰。低丰度属因为reads数少受这两种污染的影响比例远高于高丰度属。我有一批低生物量样本在调整decontam之前发现了一个相对丰度只有0.002%的“深海热液菌属”所有样本中都有看起来颇有故事性。但它其实是提取试剂盒里某种常见环境菌的16S序列。用decontam结合空白对照把它标记出来后这个“发现”彻底消失了。所以现在的习惯是低于0.01%的属除非与阳性对照或独立验证一致否则一律不写进结论。6.2 注释到属但支持度很低时宁可归为Unclassified很多流程默认把boot50作为注释阈值这会导致一批低置信度“属名”混进结果。我在差异分析之前会做一个额外的清洗步骤把boot值低于80且没有通过blast人工核查的属一律重命名为Unclassified_Genus_xxx。这样做的理由是下游统计检验不知道一个属名是否可信它只会机械地告诉你“这个标签在两个组间有差异”。如果标签本身是数据库猜测的那这个差异的生物学解释就失去了根基。清洗后我还习惯做一次敏感性分析分别用全部属表和分析清洗后的属表跑差异检验如果核心结论一致说明结果稳定如果差出好几个重要属就要回头检查注释逻辑。6.3 写报告、论文时属水平结果如何呈现更容易让人信服属水平结果的可信度很大程度取决于呈现方式。我会在方法和结果两部分都提前把注释细节说清楚。方法里写使用SILVA 138.1数据库、DADA2 assignTaxonomy注释、minBoot50或80过滤。结果部分则要交代三个数字总ASV数、成功注释到属水平的ASV比例、以及按丰度加权的注释比例。可视化方面堆叠柱状图标注top10属热图展示差异属的标准化丰度点图/柱状图展示特定属的组间比较。图中误差线表示组内样本的方差而不是标准误这样审稿人不容易质疑。图注里写明“属水平相对丰度基于ASV表聚合采用BH校正的ANCOM-BC2差异检验”这种关键信息比放一大堆星号更专业。最后再分享一个我个人的工作习惯跑完所有流程后我会把所有关键图、差异属列表、注释置信度分布汇总成一份“属水平结果速览”PDF用R Markdown自动生成。这份速览既是给合作方看的阶段性交付物也是自己三个月后快速回忆项目细节的入口。有了它整个genus综合流程才算真正闭环——所有参数固定、所有结果有出处、所有结论经得起复查。希望这套流程能让你的下一批数据少走一点弯路。
返回列表