news 2026/10/13 13:19:05

Swarm聚类实战:16S扩增子OTU分析完整流程与参数调优

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Swarm聚类实战:16S扩增子OTU分析完整流程与参数调优

1. 为什么还要聊 Swarm 这个"老家伙"

16S 扩增子测序分析这条流水线上,OTU 聚类一直是绕不开的一步。早些年大家默认用 97% 相似度切 OTU,工具换来换去无非是 QIIME 里那套 pick_otus,后来 DADA2、Deblur 这些 ASV 方法起来了,很多人觉得 OTU 聚类该进博物馆了。但实际项目里,尤其是做环境样本、发酵体系、土壤根际这类复杂度高、噪声大的数据,OTU 聚类依然有它的位置——它能把测序错误和真实低丰度物种做一个折中,结果更"稳",也更容易和旧数据对齐。

Swarm 就是在这个背景下值得单独拿出来讲的一个工具。它跟传统"先定阈值再聚类"的思路不一样,Swarm 用的是局部聚类加迭代生长的策略,不需要你一开始就拍一个 97% 的阈值,而是让序列自己"抱团",最后再根据结果去切分。这个思路在 2014 年前后发出来的时候挺惊艳的,到现在依然是很多微生物组分析流程里的可选项。

这篇文章我打算把 Swarm 的完整流程拆开讲清楚:它到底怎么聚类的、参数怎么设、跟 VSEARCH 和 QIIME 怎么配合、跑完之后 OTU 表怎么处理、常见报错怎么排查。适合已经做过 16S 分析、想换换聚类工具的人,也适合刚接手扩增子项目、需要一套能直接抄作业流程的朋友。下面所有命令和参数都是我在实际项目里跑过的,环境是 Linux 服务器,conda 管理依赖,样本量从几十到几百个都有覆盖。

2. Swarm 的聚类逻辑到底特别在哪

2.1 传统 OTU 聚类的痛点

先说说为什么会有 Swarm 这个东西。传统 OTU 聚类,不管是 cd-hit、uclust 还是 vsearch,核心逻辑都差不多:你给一个相似度阈值,比如 97%,然后算法把序列两两比对,相似度超过阈值的归为一类。听起来很合理,但问题出在"传递性"上。

举个例子,序列 A 和 B 相似度 97.5%,B 和 C 相似度 97.2%,A 和 C 相似度只有 96.1%。按阈值聚类,A、B、C 会被归成一个 OTU,因为 A-B 够、B-C 够,传递过去就成一家人了。但实际上 A 和 C 已经低于阈值了,它们可能代表两个不同的物种。这种"链式效应"在复杂样本里特别明显,会导致 OTU 数量被低估,多样性被压缩。

另一个问题是阈值本身。97% 是拍脑袋定的,不同物种的 16S 变异速率不一样,有的属内相似度就低于 97%,有的种间相似度高于 97%。一刀切必然有误判。

2.2 Swarm 的局部聚类思路

Swarm 的做法是反过来:不预设全局阈值,而是先找"种子"序列,然后让种子以 d=1 的差异向外生长,把能连上的序列吸进来,形成一个个"swarm"。这里的 d 是局部差异距离,默认 d=1,意思是每次只允许一个碱基的差异。

具体来说,Swarm 会把所有序列按丰度从高到低排序,丰度最高的那条作为第一个种子,然后找跟它差异为 1 的序列,把这些序列加进来,再找跟新加入序列差异为 1 的序列,一层层扩散,直到没有新序列能连上为止。这样就形成一个 swarm。然后从剩下的序列里再挑丰度最高的做种子,重复这个过程。

这个逻辑的好处是:它不依赖全局阈值,而是靠局部连接性来定义 OTU。链式效应依然存在,但因为是逐步生长,你可以通过调整 d 和后续的 fastidious 选项来控制粒度。而且 Swarm 会输出每个 swarm 内部的序列差异信息,你可以根据实际数据去决定要不要合并。

2.3 d=1 和 fastidious 模式的区别

Swarm 有两个主要模式:默认的 d=1 和 fastidious 模式。d=1 就是上面说的,每次只允许一个碱基差异。fastidious 模式是在 d=1 跑完之后,再做一轮"二次聚类",把那些跟已有 swarm 种子差异为 1 但之前没被吸进来的序列,重新分配过去。这一步主要是为了处理那些因为丰度太低、在第一次生长时被漏掉的序列。

实测下来,fastidious 模式会让 OTU 数量减少一些,因为很多小 swarm 会被合并到大 swarm 里。如果你的样本里有很多低丰度序列,或者你希望 OTU 数量更"保守",可以开 fastidious。如果样本比较简单,或者你更关心细微的群落差异,用默认 d=1 就行。

注意:fastidious 模式会显著增加运行时间,样本量大时慎用,或者先拿子集测试。

3. 跑 Swarm 之前的环境准备

3.1 依赖安装的几种方式

Swarm 本身是个 C++ 写的命令行工具,安装不算复杂,但依赖一些基础库。最省事的方式是用 conda:

conda create -n swarm_env -c bioconda -c conda-forge swarm vsearch seqkit conda activate swarm_env

这里我顺手把 vsearch 和 seqkit 也装上了,后面去重、排序、格式转换都要用。如果你不想用 conda,也可以从源码编译:

git clone https://github.com/torognes/swarm.git cd swarm make

编译完会在当前目录生成 swarm 可执行文件,把它加到 PATH 里就行。源码编译的好处是版本可控,坏处是如果服务器上没有 g++ 或者版本太老,会折腾一阵。

3.2 输入文件的格式要求

Swarm 接受的输入是 FASTA 格式,但有个关键要求:序列必须先去重,并且序列 ID 里要带丰度信息。通常的做法是用 vsearch 做去重和排序:

vsearch --fastx_uniques input.fasta \ --fastaout uniques.fasta \ --sizeout \ --relabel Uni \ --relabel_sha1

--sizeout会把丰度写到序列 ID 里,格式类似>Uni123;size=45。--relabel和--relabel_sha1是给序列重新命名,避免原始 ID 里的特殊字符导致 Swarm 解析出错。这一步很关键,我见过不少人直接拿原始 FASTA 跑 Swarm,结果报错说找不到 size 信息。

如果你是从 QIIME 2 的 artifact 里导出的序列,可能已经是去重过的,但 ID 格式不一定符合要求。可以用 seqkit 检查一下:

seqkit head -n 5 uniques.fasta

看序列 ID 里有没有size=字段。没有的话,用 vsearch 重新处理一遍。

3.3 参考数据库的准备

Swarm 本身只做聚类,不做物种注释。所以你需要提前准备好参考数据库,比如 SILVA、Greengenes 或者 GTDB 的 16S 子集。我一般用 SILVA 138 的 V3-V4 区域裁剪版,文件大概几百 MB。下载后解压,用 vsearch 建索引:

vsearch --makeudb_usearch silva_138_v3v4.fasta \ --output silva_138_v3v4.udb

建索引是为了后面做 taxonomy 注释时速度快一些。如果你用 QIIME 2 的 feature-classifier,那就不用自己建索引,直接导入参考序列就行。

4. Swarm 聚类的完整实操流程

4.1 第一步:序列去重与排序

假设你拿到的是双端测序拼接后的 FASTA 文件,比如merged.fasta。第一步是去重和排序:

vsearch --fastx_uniques merged.fasta \ --fastaout uniques.fasta \ --sizeout \ --relabel Uni \ --relabel_sha1 \ --minseqlength 200 \ --maxseqlength 500

这里加了长度过滤,200-500 bp 是 16S V3-V4 的常见范围。如果你的目标区域不同,调整这个范围。--relabel_sha1会用序列的 SHA1 哈希做 ID,保证唯一性。

去重完可以看一下有多少条唯一序列:

grep -c ">" uniques.fasta

通常几十个样本的去重后序列在几万到几十万条之间,取决于测序深度和样本复杂度。

4.2 第二步:Swarm 聚类

Swarm 的基本命令很简单:

swarm -f -t 8 uniques.fasta \ -o clusters.swarms \ -w clusters.fasta \ --log swarm.log

参数解释一下:

  • -f是 fastidious 模式,如果不想用可以去掉。
  • -t 8是线程数,根据服务器核数调整。
  • -o输出 swarm 列表,每行是一个 swarm 里的序列 ID。
  • -w输出代表序列,每个 swarm 一条。
  • --log输出日志,方便排查。

跑完之后,clusters.swarms里会有很多行,每行一个 swarm。行数就是 OTU 数量。clusters.fasta里是每个 OTU 的代表序列,通常是丰度最高的那条。

实操心得:Swarm 的-t参数对速度影响很大,但超过 16 之后提升不明显。如果样本量超过 200 个,建议先合并样本或者用子集测试参数。

4.3 第三步:生成 OTU 表

Swarm 本身不生成 OTU 表,需要借助 QIIME 或者自己写脚本。最方便的是用 QIIME 1 的make_otu_table.py,但 QIIME 1 现在装起来麻烦。我一般用 vsearch 或者自己写 Python 脚本。

用 vsearch 的话,可以先把 swarm 结果转成 vsearch 的格式,但更直接的是用 Python:

import sys from collections import defaultdict swarm_file = sys.argv[1] otu_map = defaultdict(list) with open(swarm_file) as f: for i, line in enumerate(f): ids = line.strip().split() for seq_id in ids: otu_map[seq_id].append(f"OTU{i+1}") # 输出 OTU 表 with open("otu_table.tsv", "w") as out: out.write("OTU_ID\t" + "\t".join([f"Sample{j+1}" for j in range(10)]) + "\n") # 这里需要根据实际样本丰度信息填充,简化示意

实际项目中,你需要把每个样本的丰度信息 merge 进来。通常的做法是先用 vsearch 生成每个样本的 count 表,然后根据 swarm 的映射关系合并。这一步比较繁琐,建议用 QIIME 2 的feature-table插件,或者用 biom 格式中转。

4.4 第四步:物种注释

拿到代表序列后,用 vsearch 做物种注释:

vsearch --usearch_global clusters.fasta \ --db silva_138_v3v4.udb \ --id 0.97 \ --blast6out taxonomy.txt \ --maxaccepts 1 \ --maxrejects 0

--id 0.97是相似度阈值,--blast6out输出 BLAST 格式的结果。然后你可以用脚本把结果转成 QIIME 的 taxonomy 格式,或者直接用 QIIME 2 的classify-consensus-vsearch。

注意:SILVA 数据库的 taxonomy 格式和 Greengenes 不一样,转换时注意层级对应关系。SILVA 用的是 D_0__、D_1__ 这种前缀,Greengenes 是 k__、p__。

5. 参数调优与结果解读

5.1 d 值怎么选

Swarm 的-d参数控制局部差异距离,默认是 1。理论上 d 越大,swarm 越少,OTU 数量越少。但 d 超过 3 之后,聚类结果会变得很粗,很多真实物种会被合并。我试过 d=1、d=2、d=3 三档,在土壤样本里 d=1 和 d=2 的 OTU 数量差大概 15%-20%,d=3 会再少 10% 左右。

一般建议:如果你做的是种水平分析,用 d=1;属水平可以试 d=2;再大就不推荐了。fastidious 模式相当于在 d=1 基础上做一次"补漏",效果介于 d=1 和 d=2 之间,但更可控。

5.2 边界序列的处理

Swarm 有个-b参数,用来控制边界序列的分配。默认情况下,如果一个序列跟多个 swarm 的种子差异都是 1,它会被分配给第一个遇到的 swarm。-b可以改成 2,让它分配给差异更小的那个。这个参数在样本复杂度高的时候有用,但会增加计算量。

5.3 结果文件的解读

跑完 Swarm 后,主要看三个文件:

文件内容用途
clusters.swarms每个 swarm 的序列 ID 列表统计 OTU 数量、计算多样性
clusters.fasta每个 swarm 的代表序列物种注释、建树
swarm.log运行日志排查错误、看运行时间

clusters.swarms的行数就是 OTU 数量。你可以用wc -l快速看一下:

wc -l clusters.swarms

如果 OTU 数量异常多(比如超过唯一序列数的 50%),可能是 d 值太小或者 fastidious 没开。如果异常少,可能是 d 值太大或者输入序列去重不彻底。

6. 常见报错与排查技巧

6.1 "Sequence ID not found" 错误

这个报错通常是因为输入 FASTA 的 ID 格式不对。Swarm 要求 ID 里必须有size=字段,或者用-z参数指定丰度列。如果你用 vsearch 去重时忘了加--sizeout,就会出这个错。解决办法是重新跑一遍 vsearch,加上--sizeout。

6.2 内存不足

Swarm 在 fastidious 模式下内存消耗比较大,尤其是序列数超过 100 万条时。如果服务器内存不够,可以先用--ceiling参数限制 swarm 的最大规模,或者分样本跑再合并。我试过 64G 内存跑 200 万条序列,fastidious 模式直接 OOM,后来改成 d=1 就没事了。

6.3 运行时间过长

Swarm 的运行时间跟序列数和 d 值都有关。d=1 时,100 万条序列大概跑 2-3 小时(8 线程);fastidious 模式会翻倍。如果时间太长,可以考虑:

  • 增加线程数(但超过 16 提升有限)
  • 先用 cd-hit 做一次粗聚类,再用 Swarm 细聚类
  • 只对高丰度序列跑 Swarm,低丰度序列单独处理

6.4 OTU 表与原始样本对不上

这个问题通常出在 OTU 表生成环节。Swarm 输出的序列 ID 是去重后的 ID,你需要把它映射回原始样本的 count 表。如果映射关系错了,OTU 表就会对不上。建议在去重时保留原始 ID 的映射文件,或者用 QIIME 2 的feature-table从头到尾管理。

避坑技巧:去重时用--relabel_sha1生成的 ID 是序列的哈希值,跟原始 ID 完全无关。如果你需要追溯,可以在去重前先用 seqkit 把原始 ID 和序列的对应关系存下来。

7. 跟其他聚类工具的对比与选择

7.1 Swarm vs VSEARCH

VSEARCH 的--cluster_size是传统的阈值聚类,速度快,适合大样本。Swarm 的局部聚类更精细,但慢。如果你的样本超过 500 个,建议用 VSEARCH 先粗聚类,再用 Swarm 对代表序列细聚类。这样兼顾速度和精度。

7.2 Swarm vs DADA2

DADA2 是 ASV 方法,不聚类,直接输出单碱基精度的序列。它的优势是分辨率高,适合种水平分析。Swarm 的优势是结果更"保守",适合跟旧数据比较。如果你做的是时间序列或者跨项目比较,Swarm 的 OTU 更稳定。

7.3 Swarm vs QIIME 2 的 vsearch 插件

QIIME 2 里的vsearch cluster-features-de-novo其实就是 VSEARCH 的封装。Swarm 没有官方 QIIME 2 插件,但可以通过q2-swarm或者手动导入。如果你重度依赖 QIIME 2 的 artifact 体系,可能需要多写一些转换脚本。

8. 我个人在实际操作中的几点体会

Swarm 这个工具,说到底是给那些"不想拍阈值"的人用的。它的局部聚类思路在理论上更优雅,但实操中你会发现,d=1 和 d=2 的结果差异可能比你想的大。我的建议是:先拿几个样本跑一遍 d=1 和 fastidious,看看 OTU 数量和物种注释的差异,再决定用哪个。

另外,Swarm 的输出文件格式比较"原始",跟 QIIME 2 的 artifact 不直接兼容。如果你要发文章或者做可重复分析,建议把 Swarm 的结果转成 biom 格式,然后用 QIIME 2 或者 phyloseq 做下游。转换脚本我一般用 Python 写,核心就是读clusters.swarms,然后根据样本 count 表填充 OTU 表。

最后再分享一个小技巧:Swarm 跑完之后,可以用seqkit stats看一下代表序列的长度分布。如果长度差异很大,说明你的去重或者过滤步骤有问题,可能需要重新检查原始数据的质量。这个检查花不了几秒钟,但能避免后面很多麻烦。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/10/13 13:18:40

反转链表就地算法:三指针迭代与高频组合套路详解

你如果去翻各大题库,会发现反转链表的就地算法几乎是出场率最高的一题。我在刷题阶段的第一道链表题就是它,当时照着别人的代码背下来,过了几天再写,还是会把链表写断。后来自己把整个"就地"过程在纸上推了三遍&#xf…

作者头像 李华
网站建设 2026/10/13 13:16:32

Excel+Power BI数据分析实战:从数据清洗到可视化看板

Excel做数据分析这事儿,看着简单,真上手了坑不少。很多人一提到数据分析就想学Python、学SQL,其实职场上90%的分析需求,Excel加上Power BI就能扛下来。我说的不是那种拿鼠标点几个按钮就完事儿的基础操作,而是真正能拿…

作者头像 李华
网站建设 2026/10/13 13:13:24

Winform在线考试系统架构设计与实现:从数据表到自动阅卷全解析

简介:一套基于Windows Forms技术开发的在线考试系统示例,专门面向C#/.NET初学者,帮助读者理解桌面端考试应用从界面设计到数据落地的完整流程。资源以zip压缩包形式提供,整体约1.25MB,便于下载后解压对照学习。系统架构…

作者头像 李华
网站建设 2026/10/13 13:10:15

虚拟地址空间与进程控制:从页表到fork/exec的底层原理与排障实践

虚拟地址空间与进程控制 刚转去做底层开发那阵子,我花了不少时间调试一个诡异的崩溃:程序跑着跑着就段错误,gdb 进去看,栈和堆的地址都很正常,可内存一旦涨到某个阈值就必挂。折腾了好几天,最后发现是某个第…

作者头像 李华
网站建设 2026/10/13 13:09:37

WinPcap 4.1.1:Windows底层原始帧收发与NDIS驱动控制实战

简介:WinPcap 4.1.1 是面向C语言网络开发者的Windows平台底层数据包捕获与分析核心库,适用于网络协议研究、安全监控工具开发、流量分析系统实现等场景,特别适合具备基础Windows驱动和Socket编程能力的中高级开发者。资源包共317个文件&#…

作者头像 李华