3. 物种丰度数据格式解读
做宏基因组分析,第一步就是跟数据格式打交道。很多新手拿到 OTU 表手忙脚乱,其实说白了,这些格式就是给物种计数搭了个架子。我个人习惯先理清三种主流格式——OTU 表、ASV 表、BIOM 格式——再加上配套的元数据文件。搞懂它们,后面的分析才能跑起来。这章我带你从头拆一遍。
OTU 表:最经典的物种丰度矩阵
OTU(Operational Taxonomic Unit)表是宏基因组分析的老牌格式。每一行代表一个分类单元(通常按 97% 序列相似度聚类),每一列代表一个样本,单元格里是序列计数或者相对丰度。你想想看,一个标准的 OTU 表长这样:
OTU_ID Sample1 Sample2 Sample3 ...
OTU_1 120 85 203
OTU_2 45 112 67
OTU_3 678 234 890
...
表格第一列是 OTU 编号,后面每列都是一个样本。行列顺序无所谓,但千万别丢了 OTU_ID 这一列。我记得有次项目里同事把第一列当成了普通数据,结果后面聚类分析全是错的。
read.csv() 或 readr::read_tsv() 读入时,记得指定 row.names = 1。这样 OTU_ID 自动变成行名,方便后续转矩阵。
ASV 表:更高精度的替代方案
这几年 ASV(Amplicon Sequence Variant)越来越流行。DADA2、Deblur 这类工具直接对扩增子序列进行单碱基分辨率的去噪,不再聚到 97% OTU。ASV 表的格式和 OTU 表一模一样,只是行名变成了 ASV_1 或实际序列哈希值。好处是分辨率更高,但稀疏性也更强。
我曾经踩过一个坑:用 DADA2 产出 ASV 表后,直接当 OTU 表往下游分析,结果在 diversity 计算时内存爆了。原因是 ASV 的行数可能是 OTU 的 5~10 倍。如果你拿到 ASV 表,我建议先了解数据量,再决定要不要合并成 OTU 做降维。
BIOM 格式:结构化生态数据标准
BIOM(Biological Observation Matrix)是 QIIME、MG-RAST 等工具通用的标准格式。它本质是一个 JSON(或 HDF5)文件,把观测表、样本元数据、特征元数据打包在一起。你不用自己手动拼,但得能看懂它的结构。
一个简化的 BIOM 片段(JSON 格式)长这样:
{
"id": "MyStudy",
"format": "Biological Observation Matrix 1.0.0",
"matrix_type": "sparse",
"shape": [3, 4],
"rows": [
{"id": "OTU_1", "metadata": {"taxonomy": ["Bacteria","Firmicutes"]}},
{"id": "OTU_2", "metadata": {"taxonomy": ["Bacteria","Bacteroidetes"]}},
{"id": "OTU_3", "metadata": {"taxonomy": ["Bacteria","Proteobacteria"]}}
],
"columns": [
{"id": "Sample1", "metadata": {"treatment":"control"}},
{"id": "Sample2", "metadata": {"treatment":"drought"}},
{"id": "Sample3", "metadata": {"treatment":"control"}},
{"id": "Sample4", "metadata": {"treatment":"drought"}}
],
"data": [[0,0,120],[0,1,45],[0,2,678],[1,0,85],[1,1,112],[1,2,234],
[2,0,203],[2,1,67],[2,2,890],[3,0,55],[3,1,99],[3,2,444]]
}
rows 是特征(OTU/ASV),columns 是样本,data 用稀疏格式存储非零值。BIOM 文件可以从 QIIME2 导出,R 里用 biomformat 包或 phyloseq::import_biom() 读取。我个人偏好先转成 phyloseq 对象,后面分析更顺。
qiime tools export 转成 1.0 格式。
元数据文件:分析成败的基石
元数据(metadata)就是样本的“身份证”。每行一个样本,每列一个变量,比如组别、时间、个体ID。一定要有第一列 SampleID,且必须和丰度表的列名一一对应。我见过最坑的是列名大小写不一致,导致合并时全部 NA。
一个标准的元数据文件:
SampleID Condition Time Weight
Sample1 Control Day0 25.3
Sample2 Drought Day0 24.8
Sample3 Control Day7 26.1
Sample4 Drought Day7 23.9
在 R 里用 read.csv() 读入,然后 dplyr::left_join() 或 phyloseq::sample_data() 关联。记住:元数据不能有空格或特殊符号,列名最好用英文加下划线,省得后面绘图报错。
格式对比速查表
| 格式 | 主要用途 | 结构特点 | 常见来源 | R 读取方式 |
|---|---|---|---|---|
| OTU 表 | 经典聚类丰度矩阵 | 行=OTU,列=样本,数值计数 | USEARCH, VSEARCH | read.csv(),指定行名 |
| ASV 表 | 去噪后高精度矩阵 | 行=ASV,列=样本,数值计数 | DADA2, Deblur | read.csv(),指定行名 |
| BIOM 格式 | 标准化打包存储 | JSON/HDF5 含观测+元数据 | QIIME2, MG-RAST | biomformat::read_biom() / phyloseq::import_biom() |
| 元数据文件 | 样本分组与属性 | 行=样本,列=变量,第一列 SampleID | 手动整理 | read.csv(),合并时注意列名类型 |
数据格式关系图
下面这张图可以帮你快速理解四种数据格式的关联与流向。
核心经验:拿到数据后,我先检查一下文件头几行。OTU/ASV 表确认第一列是 ID,BIOM 文件用 R 的 jsonlite::fromJSON() 瞥一眼结构,元数据确认 SampleID 列名没有空格和点。这些习惯能省掉后面 80% 的出错排查时间。
避坑指南
格式转换时,最容易翻车的点:
- BIOM 的
columns中id必须和元数据的 SampleID 完全匹配,包括大小写和特殊符号。 - OTU 表如果含有 NA、空值或负值,一定要提前处理,否则
phyloseq会报错。 - 元数据文件不要有隐藏的空格或不可见字符。我习惯用
readr::read_csv()代替read.csv(),因为前者能自动识别编码和 trim_ws。
好了,这四种格式是后续所有分析的基础。你只要把 OTU/ASV 表和元数据理顺,剩下的就是用 R 把它们喂给各种函数。我自己现在基本只用 phyloseq 统一管理,但脑子里始终清楚这些原始格式长什么样,因为调试时常常需要直接看 raw data。