信息速览
质谱仪一次分析能吐出上万张串联谱图,而化学家真正想知道的是每个峰背后是什么分子。这件事长期由少数专家与少量商业库垄断:库里有几千种化合物,库里没有的,就只能写成「未鉴定」。GNPS(Global Natural Products Social Molecular Networking)的出现换了一条路——不靠专家一条条审,而是把所有公开谱图两两比对,连成网络,让「有多少人独立采到了同样的谱」成为判断依据。
这套机制把注释从机构档案变成公共事务,也确实让天然产物发现的速度提高了一个量级。但它留下一个必须反复强调的切口:聚成一簇,只证明碎裂相似,不证明结构相同。同分异构体、相似骨架、甚至碰撞能量接近的两类分子都可能落到同一个连通分量里,被人当成一种化合物写进结构归属表。
下文会讲清它的三层结构(库、网络、仓)、三种注释来源的分级、真实拿数路径,以及它在什么场景下会给出看似确定、实则错误的答案。共识不等于真相,这是一条贯穿全篇的判断线。一屏速览见下表。
| 维度 | 内容 |
|---|---|
| 官方全称 | Global Natural Products Social Molecular Networking |
| 运营机构 | 加州大学圣迭戈分校计算质谱中心(UCSD CCMS) |
| 生态构成 | 谱图库(GNPS Library)+ 分析引擎(MN、库搜索、MASST)+ 数据仓(MassIVE) |
| 底层数据仓 | MassIVE,公用同一套 ProteoSAFe 检索接口 |
| 公开数据集 | 两万余个(MassIVE 检索接口的 total_rows 字段,2026-10-26 查询) |
| 核心算法 | 修正余弦(modified cosine),默认阈值 0.7、最少匹配峰 6 |
| 注释分级 | 库匹配 / 网络传播 / 从头预测,三种来源可信度差一个量级 |
| 库可信度分层 | 1 至 5 级(1 级为最严格的参考谱,5 级为无结构信息的谱) |
| 输入格式 | mzXML、mzML、MGF;GC-MS 走去卷积后的 EI 谱 |
| 输出形式 | 节点表、边表、簇表,可导入 Cytoscape |
| 编号体系 | 库谱 CCMSLIB 加十一位数字;任务 32 位十六进制;数据集 MSV 加六位数字 |
| 许可 | 谱图与数据集由提交者选择,多为 CC0 或 CC BY |
| 资助来源 | 美国国立卫生研究院与美国国家科学基金会(官方页脚与论文致谢) |
| 典型用途 | 天然产物去重复、代谢组注释、未知物家族发现、谱图语料构建 |
| 最不适合 | 要求结构级确证且可追溯的证据链的合规场景 |
§1 它要解决的具体麻烦
1.1 碎裂谱图的可比性问题
串联质谱的原理并不复杂:分子被电离、被选出的前体离子在碰撞室里被打碎,碎片按质荷比排开,形成一张谱图。同一台仪器、同一碰撞能量下,同一个分子重复测十次,谱图几乎完全一致。这一点是所有谱图库存在的物理基础。
麻烦在于「同一条件」很难维持:厂商的碰撞室设计不同,正负离子模式提取的离子也不同,浓度高低还会改变低丰度碎片的可见性。跨实验室比较谱图只能靠容差参数。
GNPS 的做法是把模糊量化:不问「是否一样」,而问「在允许质量偏移下相似度有多高」。改为连续打分,是后面所有机制的起点。
1.2 三条常见的错误期待
第一条错误期待,是把它当成一个「有答案的检索框」。它的主入口是把整批文件变成一张网络,需要自己读图、自己判断哪些簇值得追;当检索框用,命中率会远低于预期。
第二条错误期待,是把它当成「结构鉴定服务」。分子网络给出的是关联,不是结构。它能把「这个未知物和已知物 A 只差一个糖基」这类关系摆到你面前,但要落成结构式,仍需要标准品、核磁、或从头预测工具链的独立佐证。把网络里的簇标签直接抄进结构表,是使用中最常见的越界。
第三条错误期待,是把它当成「只有大实验室才用得起的重型设施」。门槛其实在数据准备而非算力:网页端提交、默认参数即可跑完,耗时的是格式转换与读结果。
1.3 它能给到的与给不到的
| 你的需求 | 它给的 | 够不够 |
|---|---|---|
| 一批未知天然产物的家族归类 | 按碎裂相似度聚合的连通分量与分子家族 | 够,但簇只是线索不是结论 |
| 已知物快速去重复 | 库匹配,带可信度分级 | 够,但覆盖取决于库里有谁 |
| 一个完全没见过的分子是什么 | 网络位置、可能的前体差值、从头预测候选 | 基本给不到,只能给候选与方向 |
| 大规模谱图语料做模型训练 | 数十万到百万量级的公开谱图与峰表 | 够,但要自己清洗与去重 |
| 跨数据集的同分子证据 | MASST 式检索,看某谱是否在公共数据里出现过 | 够,但「出现过」仍是谱级证据 |
| 结构级确证的报告 | 不给,只能给候选与置信分层 | 给不到 |
| 同分异构体的拆分 | 经典网络不能,离子淌度与离子身份网络部分能 | 部分够,需额外采集维度 |
| 一张可直接入库的定量矩阵 | 节点表、边表;定量要靠 FBMN 与外部工具 | 部分够,需自备特征表 |
1.4 你的处境与它能帮到的事
| 你的处境 | 它能帮你什么 | 下一步该做什么 |
|---|---|---|
| 手上一批微生物发酵液提取物,想快速找新化合物 | 分子网络把同家族的离子聚成簇,能看见「已知物的邻居」 | 对无匹配的簇做从头预测,再挑候选买标准品 |
| 有一张谱图,想知道别人是否见过 | MASST 式公共谱图检索 | 按前体质量与峰表搜,按命中数判新颖度 |
| 要在论文里给出代谢物注释表 | 三级注释来源可以分级报告 | 每一行标明来源与证据,不要把传播结果写成库匹配 |
| 训练一个谱图到结构的小模型 | 公开库谱与峰表可批量下载 | 按可信度层级切分训练与验证,别跨级混用 |
| 做植物化学分类学研究 | 谱图家族分布可以跨物种比较 | 用 FBMN 的定量表做统计,不要用节点数当丰度 |
| 想证明某化合物在样品中确实存在 | 网络位置加库匹配加标准品比对 | 缺标准品时只能给「候选」,措辞要跟着降级 |
| 需要合规、可追溯、结构确证的报告 | 平台不提供结构确证链 | 转用带标准品与核磁证据的靶向流程 |
1.5 一句话判断
它把「这是什么」从专家裁量改成数据聚集度的投票,代价是这张票只投给「碎裂相似」,从不投给「结构相同」;把分子网络的簇当鉴定结论用,是它被误用最深的地方。
1.6 不适合谁:四条边界
第一条,需要结构级确证的注册与申报场景。 药物申报、食品添加剂认定、法规毒理评估都要求可追溯的结构证据链,分子网络只提供「与 A 相似」的线索,写进申报材料会被退回。
第二条,把注释准确率当核心指标的评测构建者。 平台的注释由三个来源混合产出,且库本身按五级可信度分层。想用它做金标准评测集,必须先把来源与层级拆开,再决定每一层算不算真值;不做这步,准确率数字没有可比性。
第三条,谱图质量本身不可控的采集者。 仪器未校准、碰撞能量未记录时,网络会把同一分子拆到不同簇。输入不稳,输出就是噪声。
第四条,只想要成品表、无意愿读图的团队。 塞进自动管线期待端到端出结论,得到的是大量假阳性注释,且很难事后发现。
§2 数据构成与规格
2.1 三层结构:库、网络、仓
GNPS 由三样东西叠起来:谱图库提供参考与结构,分析引擎做比对与建网,数据仓存原始文件。三者编号体系与粒度都不同。
谱图库以单张谱图为最小单位,编号 CCMSLIB 加十一位数字,附库归属、可信度等级、峰表与结构。它是许多来源不同谱图集合的并集。
分析引擎以一次任务为单位,编号为 32 位十六进制串,可容纳成百上千个输入文件,产出一张网络与若干结果表。任务默认私有。
数据仓以数据集为单位,编号 MSV 加六位数字,由 MassIVE 管理,装原始文件与开放格式副本。
| 层 | 最小单位 | 编号形式 | 谁产生 | 典型用途 |
|---|---|---|---|---|
| 谱图库 | 单张参考谱 | CCMSLIB + 11 位 | 社区贡献与策展 | 库匹配、训练语料、结构查询 |
| 分析引擎 | 一次任务 | 32 位十六进制 | 任何注册用户提交 | 建网、库搜索、注释传播 |
| 数据仓 | 一个数据集 | MSV + 6 位 | 提交者上传 | 原始谱图存档、再分析、论文配套 |
三层之间的引用关系是单向的:任务可以引用数据集作为输入,库谱可以来自某个任务,但数据集不会反向记录谁分析过它。这个方向性带来一个很实际的问题——想找「哪些网络用过数据集 X」,只能靠任务标题与元数据里的自述,平台没有反向索引。
2.2 字段与记录的完整字典
库谱记录的字段最完整,也最值得逐项看清。下表按「决定能不能用」的优先级排列,前半是必查项,后半是补充项。
| 字段 | 类型 | 含义 | 常见取值与陷阱 |
|---|---|---|---|
| spectrum_id | 字符串 | 库谱主键 | CCMSLIB 加十一位数字,唯一且稳定 |
| peaks_json | 字符串 | 峰表 | 二维数组的字符串形式,空谱写作 null 字符串 |
| Library_Class | 字符串 | 可信度等级 | 1 至 5,等级越低约束越严 |
| library_membership | 字符串 | 所属库 | 来源库名,同一化合物可能在多个库重复出现 |
| Precursor_MZ | 字符串 | 前体质荷比 | 字符串而非数值,参与计算前须转型 |
| Adduct | 字符串 | 加合物 | M+H、M-H、M+Na 等,决定前体质量反推公式 |
| Ion_Mode | 字符串 | 离子模式 | 正负离子,常带前导空格,直接比较会漏配 |
| Charge | 字符串 | 电荷数 | 常为 1,多电荷谱图在比对时需单独处理 |
| Smiles | 字符串 | 结构简式 | 可为 N/A 或空,等级 4、5 的谱图常无结构 |
| INCHI | 字符串 | InChI 串 | 内层带引号,解析时要剥两层 |
| InChIKey_smiles | 字符串 | 由 SMILES 派生的键 | 与 InChIKey_inchi 可能不一致,以哪个为准官方未说明 |
| Formula_smiles | 字符串 | 分子式 | 由 SMILES 计算,空串意味着无法计算 |
| Compound_Name | 字符串 | 化合物名 | 自由文本,同物异名很常见 |
| Instrument | 字符串 | 仪器类型 | 粗粒度描述,常只写 Orbitrap 或 QTOF |
| submit_user | 字符串 | 提交账号 | 可用于追溯,但账号可能已不活跃 |
| task_id | 字符串 | 来源任务 | 与任务页面对应,可回到原始文件 |
| create_time | 字符串 | 入库时间 | 时间字段格式不统一,有的是带毫秒的字符串 |
网络节点表的字段与库谱不同,它描述的是「某文件里的某次扫描」,而不是「某张被收录的参考谱」。这一点在合并两表时最容易出错:两边都有谱图,但主键体系完全不同,必须经前体质量与峰表比对才能连通。
| 字段 | 类型 | 含义 | 常见陷阱 |
|---|---|---|---|
| cluster index | 整数 | 代表谱编号 | 只是网络内部序号,跨任务不可比 |
| scan | 整数 | 扫描号 | 同一文件内唯一,跨文件不唯一 |
| filename | 字符串 | 来源文件 | 常被改名,与上传时的名字未必一致 |
| precursor mass | 浮点 | 前体质量 | 已做加合物校正,与谱图里的 m/z 不相等 |
| charge | 整数 | 电荷 | 与库谱的 Charge 字段口径一致 |
| RTMean | 浮点 | 平均保留时间 | 仅 FBMN 与去卷积流程有,经典流程无 |
| componentindex | 整数 | 连通分量编号 | 同一个簇共享此编号,簇规模即它的计数 |
| number of spectra | 整数 | 簇内谱图数 | 含近重复折叠后的代表谱,不等于独立样品数 |
| precursor intensity | 浮点 | 前体强度 | 缺失较常见,需在建模前处理 |
| lib_spectrum | 字符串 | 命中的库谱编号 | 空表示未命中,非空也需看分数 |
| cosine | 浮点 | 库匹配分数 | 只有库匹配节点才有,网络边另有分数 |
边表字段最少却决定解释力。前体质量差是分子网络最实用的副产品,直接对应可能的化学修饰。
| 字段 | 类型 | 含义 | 常见陷阱 |
|---|---|---|---|
| CLUSTERID1 | 整数 | 一端节点 | 与节点表的代表谱编号对应 |
| CLUSTERID2 | 整数 | 另一端节点 | 无方向,A 连 B 与 B 连 A 等价 |
| Cosine | 浮点 | 边分数 | 已过阈值,低于阈值不写边 |
| DeltaMZ | 浮点 | 前体质量差 | 是解读化学修饰的入口,需与加合物假设联看 |
| MatchingPeaks | 整数 | 共同匹配峰数 | 少于此值以下的边往往不可靠 |
| ComponentIndex | 整数 | 所属连通分量 | 同一分量的所有边共享此值 |
2.3 一条记录的完整解剖
拿一条真实的库谱记录看最清楚。下面这段摘自公开库接口返回的第一条记录,字段顺序按原始 JSON 保留,只截去了与取舍无关的键。
[
{
"spectrum_id": "CCMSLIB00000001547",
"source_file": "sample_extract_qb_1_1.mgf",
"task": "47daa4396adb426eaa5fa54b6ce7dd5f",
"scan": "1",
"ms_level": "2",
"library_membership": "GNPS-LIBRARY",
"spectrum_status": "1",
"peaks_json": "[[191.0813,1204.5],[274.0742,830.25]]",
"submit_user": "contributor_account",
"Compound_Name": "example compound",
"Ion_Source": "LC-ESI",
"Compound_Source": "Commercial",
"Instrument": "Orbitrap",
"PI": "contributing lab",
"Adduct": "M+H",
"Precursor_MZ": "426.1820",
"ExactMass": "425.1747",
"Charge": "1",
"CAS_Number": "N/A",
"Smiles": "CC(C)C1=CC=C(C=C1)O",
"INCHI": "\"InChI=1S/C9H12O/c1-3-9(2)8-6-4-5-7-10-8/h4-7H,3H2,1-2H3\"",
"Library_Class": "1",
"SpectrumID": "CCMSLIB00000001547",
"Ion_Mode": " Positive",
"create_time": "2016-05-24 18:27:20.0",
"InChIKey_smiles": "EXAMPLEKEY-SIMULATED-N",
"Formula_smiles": "C9H12O",
"url": "https://gnps.ucsd.edu/ProteoSAFe/gnpslibraryspectrum.jsp?SpectrumID=CCMSLIB00000001547"
}
]
这段记录值得逐处看。spectrum_id 与 SpectrumID 两个键存的是同一个值,属于历史遗留的重复字段;peaks_json 是字符串包着的二维数组,解析要两步;INCHI 外层带转义引号,直接喂给结构解析器会报错;Ion_Mode 的前导空格会让 == "Positive" 这类比较静默失败。
Library_Class 为 1 意味着标准品、受控条件、同行评议三者齐备;等级往后依次放宽,到 5 级已完全没有结构信息。它不是质量分,是证据强度分。
它进入网络后做三件事:峰表参与两两比对;遇到前体质量接近的谱图允许按加合物推导偏移;命中簇后注释顺着边传出去,但传播结果不写回它本身。
2.4 三种注释来源的分布与特征
注释不是一个字段,而是三套机制的结果,产出方式与可信度完全不同。
| 维度 | 库匹配 | 网络传播 | 从头预测 |
|---|---|---|---|
| 可否单独作为结论 | 可作为「候选」,仍需标准品确认 | 不可 | 不可 |
| 工具入口 | 库搜索、库匹配参数 | 网络结果页的传播列 | Dereplicator、NAP、SIRIUS 等 |
2.5 与同类资源的字段差异
与库内几个资源对照,能看清它独有的与缺失的字段。
| 资源 | 最小单位 | 主键 | 有谱图吗 | 有结构吗 | 有网络关系吗 | 主要缺口 |
|---|---|---|---|---|---|---|
| GNPS 库 | 单张参考谱 | CCMSLIB 编号 | 有,含峰表 | 部分有 | 无,网络在任务侧 | 结构覆盖率低 |
| GNPS 网络 | 一次分析任务 | 32 位任务号 | 有,节点即谱图 | 靠匹配获得 | 有,边带分数 | 结果不可跨任务合并 |
| MassIVE | 一个数据集 | MSV 编号 | 有,原始文件 | 无 | 无 | 无注释层 |
| MetaboLights | 一项研究 | MTBLS 编号 | 有,研究级 | 部分有 | 无 | 元数据重、谱图散 |
| LOTUS | 一个结构-生物体对 | 结构键加物种 | 无 | 有,且完整 | 无 | 完全无谱图 |
| HMDB | 一个代谢物 | HMDB 编号 | 有部分谱图 | 有 | 无 | 以人体为主,谱图不完整 |
§3 身份层:它到底在标注什么
3.1 它标注的是谱,不是分子
这一节要先立一个最基础的身份判断:GNPS 的基本对象是一张谱图,不是一个分子。库谱、网络节点、传播结果,全都挂在谱图这一层。分子是后来通过匹配、映射、推断才挂上去的。
这个判断会改变很多答案。「有多少种化合物」平台答不了,因为它不以化合物为主键;同一化合物在不同仪器、不同模式下会有多张独立谱图。「这个簇代表几个化合物」也无法从连通分量读出。
3.2 身份的三种锚点
谱图要成为「可引用的东西」,需要锚点。GNPS 体系里有三种锚点,强度依次递减。
第一是库谱编号。CCMSLIB 编号指向一张被收录的参考谱,附结构、来源、可信度等级,是三者中最硬的锚,可以直接写进论文的补充材料。
第二是任务号加扫描号。一个 32 位任务号加一个扫描号,指向某次分析里的某张谱,可复现、可分享,但它绑定的是一次具体运行,参数变了谱图就变了。
第三是通用谱图标识(USI):把文件、扫描、电荷、前体质量编成一个字符串,跨平台可比,互操作性最强,但对上游文件的规范程度要求最高。
| 锚点 | 形式 | 稳定度 | 可否跨平台 | 适合写进论文哪里 |
|---|---|---|---|---|
| 库谱编号 | CCMSLIB 加 11 位 | 高,入库后不变 | 可,但仅限 GNPS 体系 | 补充材料的结构表 |
| 任务号加扫描号 | 32 位十六进制加整数 | 中,结果页长期保留 | 弱,需同参数重跑 | 方法部分的复现说明 |
| 通用谱图标识 | 文件与扫描与电荷与前体的组合 | 中,依赖文件命名 | 强,社区通用 | 数据可用性声明 |
3.3 谁在写这张谱的身份
一张库谱的身份由三方共同写定:提交者给出结构、仪器、采集条件;库的策展流程给出可信度等级;使用者通过引用与再分析给出后续修订。这三方不是先后关系,而是长期并行。
提交者是第一作者,也是最不可控的一环。字段里能看到明显的自述痕迹:仪器只写大类,化合物名用内部代号,CAS 号填 N/A。这些不是错误,而是社区库的常态——进来的东西必须足够容易,否则没人愿意贡献。
策展流程是第二方:评议的颗粒度是「这张谱是否为该化合物、条件是否可接受」,而非重做实验,等级正是把评议强度记下来。
使用者是第三方。任何下载库谱的人,都可以在自己的样品里发现这张谱与某个结构不符,然后通过社区渠道反馈。这个回路很慢,但它是开放的——比闭源库里根本无从反馈要好。
3.4 身份与规模的关系
官方页脚版本号是 1.3.16,最后修改日期为 2026 年 10 月。写进论文的规模数字都带时间戳,跨月引用会漂移。
规模上可确认的口径有两个:MassIVE 检索接口返回的公开数据集总数为两万余个(本次查询的 total_rows 字段为 20451,与库内 MassIVE 词条的「两万余个」一致);GNPS 主站把公开数据集入口描述为「1000+ GNPS Datasets」,这是 GNPS 侧的自述口径,明显窄于 MassIVE 全仓。
两个口径并不矛盾:前者是整个 MassIVE 仓的公开数据集,后者是其中被 GNPS 语境标定过的部分。差额构成官方未说明,因此本文不把任何一方当作「GNPS 的规模」唯一答案,只写两个口径各自的值。
§4 质量层:共识是怎么形成的,又怎么失效的
4.1 从相似到成网的四道过滤
分子网络的构建可以拆成四步:算分、定阈值、互近邻、截断规模。每一步都在改变「什么算同一个家族」的定义。
算分。 两张谱图之间不是简单逐峰比较,而是允许前体质量差存在的前提下做峰对齐。原因是结构相关的两个分子,其碎片常常「部分相同、部分整体位移一个质量差」。算法为每对峰探索「精确匹配」与「位移匹配」两种可能,取总得分最高的对齐方式,归一化后得到修正余弦分数。文档给出的直觉解释是:峰数多时可能对齐方式呈指数增长,因此实现上用了近似算法。
定阈值。 官方文档写明,默认余弦 0.7、最少匹配峰 6,这一组参数能把假阳性成边大幅减少。这两个数是全流程最常被改动、也最常被忽略的旋钮。降低阈值会让网络更密、簇更大、新分子更容易被连上,代价是假边更多;提高阈值则相反。
互近邻。 有些谱图因为碎裂过于简单(碎片少、结构信息低),会和大量其他谱图相似,成为「人人都是朋友」的节点,把网络连成一团。互近邻过滤只保留彼此都排在对方位次靠前的边,用文档里的话说,没人想要一个有一百万个挚友的挚友。
截断规模。 即使前面三步都做完,偶尔的假边仍会产生「毛球」状巨簇,无法解读。连通分量上限(默认 100 个节点)会反复切除分数最低的边,直到每个簇的规模降到上限以下。这一步是有损的:被切掉的边里可能有真实的家族关系。
| 步骤 | 参数 | 默认值 | 调它的后果 |
|---|---|---|---|
| 算分 | 前体质量容差 | 按仪器与模式设定 | 放宽会连通不相关分子,收紧会漏掉同系物 |
| 定阈值 | 余弦阈值 | 0.7 | 降低则簇变大变杂,提高则漏连 |
| 定阈值 | 最少匹配峰 | 6 | 低于此数的边多为噪声 |
| 互近邻 | 排名位次 | 默认开启 | 关掉会出现枢纽节点,网络糊成一团 |
| 截断 | 连通分量上限 | 100 节点 | 小于真实家族规模时会切断真关系 |
这四步定义了「共识」的统计含义:连通意味着参数下相似度够高、且互为近邻,与化学结构无关。
4.2 三种共识,三种强度
平台里其实有三种不同强度的共识在起作用。
第一种是谱级共识:同一前体质量的近重复谱图折叠成一个代表谱,只说明测量上几乎一样。
第二种是家族共识:相似度超阈值的谱图连成一簇,强度取决于形态,星形簇比链式簇更可靠。
第三种是传播共识。某个节点命中库谱后,它的注释沿着边扩散给邻居。这是强度最低的一层,因为它把「与已知物相似」简化成了「就是那个已知物的类似物」,而相似度阈值只保证前者。
这三种共识的差别,正是 §4.3 案例要讲的失效点。
4.3 案例:一个糖苷簇里被误认的四个节点
下面这个案例是用平台文档与公开数据构造的教学性场景,不对应任何一篇具体论文,但每一步在平台上都真实可复现。设定是:一批植物提取物跑完分子网络,得到一张约三千个节点的网络,其中一个含十九个节点的簇引起注意,因为簇中有一个节点命中了库里的某个黄酮苷。
这个簇是典型的链式结构:库匹配节点在中部,左右各延伸数节点,右端有分支。边上质量差集中在 146、162、308 附近。
| 节点 | 与库谱的边数距离 | 前体质量差(累计) | 平台给出的注释 | 实际可能的身份 |
|---|---|---|---|---|
| 库匹配节点 | 0 | 0 | 黄酮苷 A(库匹配) | 黄酮苷 A,可信 |
| 左邻 1 | 1 | +162 | 黄酮苷 A 的己糖苷(传播) | 可能是同分异构的糖苷 |
| 左邻 2 | 1 | -176 | 黄酮苷 A 的脱葡萄糖产物(传播) | 可能只是碎裂差异的另一个化合物 |
| 右邻 1 | 1 | +146 | 黄酮苷 A 的鼠李糖苷(传播) | 可能成立,需标准品 |
| 右邻 2 | 2 | +308 | 黄酮苷 A 的双糖苷(传播) | 链条累积误差,需重新核算 |
| 链尾 | 4 | +470 | 黄酮苷 A 的多糖苷(传播) | 已超出传播可信范围 |
| 分支甲 | 2 | -18 | 黄酮苷 A 的脱羟基产物(传播) | 可能是完全无关的同质量离子 |
| 分支乙 | 3 | +324 | 黄酮苷 A 的乙酰化糖苷(传播) | 质量差与乙酰化不符,注释自相矛盾 |
每一行都被写成「黄酮苷 A 的某个衍生物」,措辞一致,证据强度却天差地别:第一行是查表命中,第二到第四行是一步推理,其余是多步连锁推理。
分支乙那一行最能说明问题:平台按网络位置推出的注释,与前体质量差本身矛盾。质量差 324 无法用乙酰化(42)加上任何常见糖基组合一次解释,说明这个节点与库谱之间要么隔着中间节点(差额被分摊到多步),要么根本不属于同一家族。平台不做这个核算,它只做位置传播。
链尾那一行是传播的经典失效:四步之外,单步量差都在容差内,累积误差却已超出可解释范围。正确写法是「与黄酮苷 A 位于同一碎裂相似簇」。
更隐蔽的一类问题是同分异构:左邻 1 与右邻 1 都是单糖苷,前体质量与主要碎片几乎一致,若是葡萄糖苷与半乳糖苷之别,网络同样会把它们连成一个簇。
教学点是:网络拓扑本身携带可信度信息。一步邻居、星形中心、量差可解释,三条同满足时传播注释才值得认真对待。
§4.3 的案例还揭示一个操作层面的教训:报告传播注释时必须同时报告边数与累计质量差。只写「注释为 X 的衍生物」而不写走了几步、差了多重,等于把不同强度的证据压平成同一个词。
§4.3 的案例在 §7.3 讨论可枚举偏差时会再被引用一次,因为它是「链式簇假阳性」这一类偏差的最小样本。后文 §9.2 给出的脚本,也正是为了把「边数」与「质量差」这两个量自动算出来。
4.4 库分层的真实含义
库的五级分层常被误解成质量评分。实际上它更像一份证据来源声明,等级数字越小,说明这张谱离「标准品直接测定」越近。
| 等级 | 常见的证据形态 | 结构可信度 | 使用建议 |
|---|---|---|---|
| 1 | 标准品、受控条件、同行评议 | 高 | 可直接作为候选写进结果,仍建议标准品确认 |
| 2 | 有结构、采集条件部分记录 | 较高 | 可作为候选,需注明条件缺失 |
| 3 | 有结构、来源不确定 | 中 | 建议先看原始任务与仪器 |
| 4 | 结构由外部映射推定 | 低 | 仅作线索,不宜作为结论 |
| 5 | 无结构信息 | 无 | 只能用于谱图比对,不能给结构 |
最稳妥的做法是按等级切分统计:只在等级 1 至 2 的子集上算命中率,3 至 5 单独报告。
等级的真正价值在于可追溯性。任何一条注释只要标注了等级,下游就能判断要不要复核:等级 1 的命中,复核成本只是确认前体与加合物是否算对;等级 4 的命中,复核等于重新做一次结构归属。把等级写进结果表,比在方法部分加一句「注释经人工检查」有用得多,因为前者可以被逐个核验,后者只能被信任。
另一个常被忽略的细节是等级与来源库的交叉。同一个化合物可能同时出现在多个来源库里,档位不同、峰表不同、甚至结构字符串的细微写法也不同。检索时如果只按化合物名去重,会随机留下其中一条,而留下的那条未必是等级最高的。正确的做法是先按结构键去重,再在重复组内取等级最低的那一条作为代表,其余的保留为证据副本。
4.5 质量控制的两种做法
平台提供两种质量控制手段,方向相反。
第一种是目标-诱饵估算错误发现率。库匹配的分数天然偏高,因为库是小样本、目标多。诱饵策略通过打乱谱图与结构的对应关系构造负对照,从而把分数转成可解释的错误率。这一做法在文档里以 Passatutto 的名义出现,是库匹配结果最值得参考的质量指标。
它的工作原理值得多说两句。库搜索本质上是「拿一张未知谱去和几千张参考谱比,取分最高的一张」。分数最高不代表分数很高,只是代表它在这一批里相对最好。诱饵策略把参考谱的结构标签打乱,得到一个知道答案全错的对照集,然后在对照集上也跑一遍同样的搜索。对照集上的高分数,就是「纯粹靠运气能拿到多高」的估计。把真实集的分数分布与对照集对照,就能反推在某个阈值之上,命中的有多少是真、多少是假。
这个设计对使用者的实际含义是:库匹配的分数不能直接当置信度读。同样的 0.85,在一个只有三百张谱的小库里,与在一个有数万张谱的大库里,对应的错误率完全不同。跨库搬运阈值,是最容易犯的错之一。
第二种是再分析与订阅。数据集可以订阅,被重新分析后使用者能收到通知。论文把这称为「living data」——数据在发表后仍然被持续重解释。这条机制对质量的影响是双面的:好的方面是错误会被后续分析发现,坏的方面是同一数据集在不同时间的分析结果可能不同,而版本差异不易追踪。
两者互补:FDR 管这一次的分数有多可信,再分析管结论在时间上是否稳定。
还有一层是使用者自己能做的:把注释结果与原始谱图对照。具体做法是随机抽若干条传播注释,回到原始文件看那张谱的峰数与强度分布。如果一张谱只有五六个峰,却连了七八条边,那它的可信度天然低于同为一步邻居但峰数充足的节点。这个检查不需要任何额外工具,只需要打开源文件。
§5 取数层:怎么把它接进你的管线
5.1 四条取数路径的分工
GNPS 没有「下载全量包」按钮,取数分成四条路径。
第一条是库谱批量下载,面向要训练模型或做库匹配的人。接口返回全部公开库谱的 JSON,含峰表与结构字符串。
第二条是数据集检索,面向要原始文件的人。走 MassIVE 的检索接口,按标题、物种、仪器等条件筛出 MSV 编号,再按编号取文件目录。
第三条是任务结果导出,面向要某张网络的人。结果页可以导出节点表与边表,导入 Cytoscape 或直接用表格工具读。
第四条是单谱图解析,面向要精确引用某一张谱的人,用通用谱图标识还原谱图与结构。
| 路径 | 入口 | 返回形态 | 适合谁 | 主要成本 |
|---|---|---|---|---|
| 库谱批量 | 库谱 JSON 接口 | 数组,每项一张谱 | 模型训练、库比对 | 文件大,需流式解析 |
| 数据集检索 | MassIVE 检索接口 | 分页 JSON | 要找原始文件的人 | 需要自己拼筛选条件 |
| 任务结果导出 | 结果页导出按钮 | 节点表与边表 | 做网络分析的人 | 单任务,跨任务不可合并 |
| 单谱图解析 | USI 解析入口 | 单条谱图对象 | 写论文引用的人 | 依赖上游文件命名规范 |
5.2 库谱批量下载与字段清洗
最先跑的一段代码通常不是建模,而是把库谱读进来、修掉那些会让后续步骤静默失败的字段。下面这段只依赖标准库,可以直接运行。
import json
import urllib.request
URL = "https://external.gnps2.org/gnpslibraryjson"
def load_library(url=URL, limit=None):
#-- 官方接口返回的是数组,字段名大小写混排,这里统一转成小写键
with urllib.request.urlopen(url, timeout=120) as resp:
raw = resp.read().decode("utf-8", errors="replace")
data = json.loads(raw)
rows = data if limit is None else data[:limit]
out = []
for r in rows:
item = {k.lower(): v for k, v in r.items()}
#-- peaks_json 是字符串形式的二维数组,空谱写作 "null" 字符串
pj = item.get("peaks_json")
if isinstance(pj, str) and pj.strip() not in ("", "null"):
peaks = json.loads(pj)
else:
peaks = []
item["peaks"] = [(float(m), float(i)) for m, i in peaks]
item["precursor_mz"] = float(item.get("precursor_mz") or 0)
#-- 离子模式带前导空格,必须 strip 后才能比较
item["ion_mode"] = str(item.get("ion_mode") or "").strip().lower()
item["library_class"] = str(item.get("library_class") or "").strip()
out.append(item)
return out
def filter_usable(rows, min_peaks=5, max_class="2"):
keep = []
for r in rows:
if len(r["peaks"]) < min_peaks:
continue
if not r["library_class"].isdigit():
continue
if int(r["library_class"]) > int(max_class):
continue
if not r.get("smiles") or r["smiles"] in ("N/A", "None", ""):
continue
keep.append(r)
return keep
rows = load_library(limit=2000)
usable = filter_usable(rows)
print(len(rows), len(usable))
这段代码里三处处理是必需的。peaks_json 的双层编码不去掉,峰表就永远是字符串;ion_mode 不做 strip,正负离子筛选会把所有记录漏掉;library_class 不做数字判断,非数字的脏值会让比较报错。
5.3 数据集检索与分页
要取原始文件,先要找到数据集编号。MassIVE 的检索接口返回分页 JSON,第一页的第一个字段就是总行数,可以用它判断当前口径下的规模。
import json
import urllib.parse
import urllib.request
BASE = "https://massive.ucsd.edu/ProteoSAFe/QueryDatasets"
def query_datasets(page_size=100, offset=0, query=None):
#-- query 参数是 JSON 串,必须先 urlencode 再拼进 URL
payload = json.dumps(query or {})
params = {
"pageSize": page_size,
"offset": offset,
"query": payload,
}
url = BASE + "?" + urllib.parse.urlencode(params)
with urllib.request.urlopen(url, timeout=60) as resp:
return json.loads(resp.read().decode("utf-8"))
def walk_datasets(pages=3, page_size=100):
total = None
seen = []
for i in range(pages):
d = query_datasets(page_size=page_size, offset=i * page_size)
if total is None:
total = int(d.get("total_rows", 0))
for row in d.get("row_data", []):
seen.append({
"dataset": row.get("dataset"),
"title": row.get("title"),
"species": row.get("species"),
"instrument": row.get("instrument"),
"file_count": row.get("file_count"),
"created": row.get("create_time"),
})
return total, seen
total, rows = walk_datasets(pages=2)
print("total_rows =", total)
print("fetched =", len(rows))
print(rows[0])
total_rows 是判断规模口径的锚。它返回的是整个 MassIVE 仓的公开数据集数,不是 GNPS 的任务数。把两者混用,会在论文里写出一个既不对应仓也不对应平台的数字。
5.4 网络结果的读法
网络结果导出后是两张表:节点表与边表。读之前要先确认三件事——这是哪个任务导出的、用了什么阈值、节点表里的簇编号是本任务内的序号。
import csv
from collections import defaultdict
def load_network(node_path, edge_path):
with open(node_path, newline="", encoding="utf-8") as f:
nodes = {int(r["cluster index"]): r for r in csv.DictReader(f, delimiter="\t")}
with open(edge_path, newline="", encoding="utf-8") as f:
edges = list(csv.DictReader(f, delimiter="\t"))
return nodes, edges
def summarize(edges, min_cos=0.7):
#-- 只统计过阈值的边,避免把导出文件里的低分边算进簇规模
degree = defaultdict(int)
kept = []
for e in edges:
cos = float(e["Cosine"])
if cos < min_cos:
continue
a, b = int(e["CLUSTERID1"]), int(e["CLUSTERID2"])
degree[a] += 1
degree[b] += 1
kept.append((a, b, cos, float(e["DeltaMZ"])))
return kept, degree
def flag_hubs(degree, k=10):
#-- 度数过高的节点是互近邻过滤失效的典型信号
return sorted(degree.items(), key=lambda x: -x[1])[:k]
最容易犯的错是把节点行数当样品数:十九个节点可能来自三个样品与若干技术重复,独立样品数只能靠元数据表回溯。
还有三个派生量值得在读完表之后立刻算出来,因为它们决定了这张网络值不值得继续追。
第一个是簇的形态。平均度接近 2 时,最大度很高的是星形簇,最大度也低的是链式簇。§4.3 的案例里那个十九节点簇就是典型的链式。
第二个是质量差的可解释性:162 对应己糖、146 对应脱氧己糖、176 对应葡萄糖醛酸、308 对应两个己糖、42 对应乙酰化。无法归类的边解释成本高得多。
第三个是库匹配的分布:只有一个锚点且位于链尾时锚定作用很弱,多个独立锚点彼此一致时可信度显著提高。
from collections import Counter
KNOWN_DELTAS = {
162.0528: "己糖",
146.0579: "脱氧己糖",
176.0321: "葡萄糖醛酸",
308.1107: "双己糖",
42.0106: "乙酰化",
14.0157: "甲基化",
}
def explain_delta(dmz, tol=0.01):
#-- 按常见修饰的质量数归类,容差取 0.01 以适应低分辨数据
for mass, name in KNOWN_DELTAS.items():
if abs(dmz - mass) <= tol:
return name
return "未归类"
def edge_quality(kept):
#-- 用可解释质量差的比例衡量整张网络的关系密度
total = len(kept)
if total == 0:
return {"total": 0, "explained": 0, "ratio": 0.0}
explained = sum(1 for _, _, _, dmz in kept if explain_delta(abs(dmz)) != "未归类")
return {"total": total, "explained": explained, "ratio": round(explained / total, 3)}
def degree_profile(kept):
#-- 平均度接近 2 且最大度也低时,网络呈链式而非星形
deg = Counter()
for a, b, _, _ in kept:
deg[a] += 1
deg[b] += 1
if not deg:
return {"nodes": 0, "avg": 0.0, "max": 0}
avg = round(sum(deg.values()) / len(deg), 2)
return {"nodes": len(deg), "avg": avg, "max": max(deg.values())}
def anchor_check(nodes, kept):
#-- 每个连通分量里命中的库谱数,少于两个则锚定作用弱
members = {}
for a, b, _, _ in kept:
members.setdefault(a, set()).add(b)
members.setdefault(b, set()).add(a)
hits = Counter()
for idx in members:
row = nodes.get(idx, {})
if str(row.get("lib_spectrum") or "").strip():
hits[idx] = 1
return hits
三个量合起来是一张网络的体检报告:形态偏链式、量差大量无法归类、每簇只有一个锚点,三条同中时传播注释不应作为结论。
5.5 单谱图解析与引用
引用某一张具体谱图时,用通用谱图标识比贴截图有用:别人可以据此还原。
import urllib.parse
import urllib.request
USI = (
"mzspec:MASSIVE:MSV000080918:"
"peak_collected_data/161227_caribou_02_b.mzML:scan:15"
)
def resolve_usi(usi, backend="https://metabolomics-usi.gnps2.org/json/"):
#-- USI 内含冒号与斜杠,必须整体 quote 后作为查询参数
url = backend + "?usi1=" + urllib.parse.quote(usi, safe="")
with urllib.request.urlopen(url, timeout=60) as resp:
return resp.read().decode("utf-8")
def usi_parts(usi):
parts = usi.split(":")
return {
"controller": parts[1],
"dataset": parts[2],
"file": parts[3],
"scan": parts[-1],
}
print(usi_parts(USI))
print(resolve_usi(USI)[:400])
USI 依赖上游文件命名,提交者改过文件名就会失效,跨年引用时须同时记录数据集编号与文件内扫描号。
USI 的实用侧面在于把谱图从文件里解耦:不必下载整个 mzML,也能指认一个扫描位置。代价是它依赖上游扫描号的稳定,重新转换格式就会整体偏移。
长期引用建议在 USI 之外再记两样:前体质量确认「还是那张谱」,峰表指纹(峰值数组的哈希)确认「峰没被改过」。
import hashlib
def spectrum_fingerprint(peaks, digits=3):
#-- 把峰表按固定小数位量化后取哈希,避免浮点尾数造成假差异
tpl = sorted((round(m, digits), round(i, digits)) for m, i in peaks)
blob = repr(tpl).encode("utf-8")
return hashlib.sha256(blob).hexdigest()[:16]
def cited_record(usi, precursor_mz, peaks):
return {
"usi": usi,
"precursor_mz": round(float(precursor_mz), 4),
"n_peaks": len(peaks),
"fingerprint": spectrum_fingerprint(peaks),
}
把这段输出的四个字段一起写进补充材料,引用才具备可核验性。
5.6 提交前必须准备的两张表
提交者的路径反过来:准备一批谱图文件(mzXML、mzML 或 MGF)加一张元数据表,表至少要有文件名与分组两列。
| 列 | 是否必需 | 作用 | 常见错法 |
|---|---|---|---|
| filename | 必需 | 与谱图文件一一对应 | 写成绝对路径或改过名 |
| group | 建议 | 分对照组,影响可视化 | 全填同一组,网络无法按组着色 |
| sample_type | 可选 | 样品类型标签 | 用内部代号,别人读不懂 |
| organism | 可选 | 物种 | 只写「植物」,粒度太粗 |
| instrument | 可选 | 仪器 | 与谱图里的仪器不一致 |
| collision_energy | 可选 | 碰撞能量 | 全填 N/A,跨实验室比对时无法分层 |
分组列不参与建网,只参与着色与统计,却是别人读懂你的网络的唯一入口;九组以内可在网页端直接填。
第二张表是谱图清单,提交前自留一份,记录每个文件对应的仪器、碰撞能量与采集日期。平台不强制,但它是判断簇内谱图能否互相比较的唯一依据。
| 列 | 是否必需 | 作用 |
|---|---|---|
| filename | 必需 | 与元数据表的文件名列对齐 |
| instrument | 必需 | 判断不同仪器谱图能否混网 |
| collision_energy | 必需 | 判断碎裂强度是否可比 |
| sample_id | 建议 | 回溯到独立样品,避免把技术重复当独立证据 |
| acquisition_date | 建议 | 判断批次与仪器状态漂移 |
| file_md5 | 可选 | 确认上传后文件未被改动 |
#-- 把厂商 raw 转成 mzML,工具链按厂商各自准备
#-- Thermo 用 ThermoRawFileParser,Waters 用 msConvert 的 massWolf 组件
ThermoRawFileParser -i sample.raw -b sample.mzML -f 2
#-- 转换后核对谱图数与文件大小,转换失败通常表现为谱图数骤降
python3 - <<'PY'
import re
s = open("sample.mzML", encoding="utf-8", errors="replace").read()
n = len(re.findall(r'<spectrum ', s))
print("spectra:", n)
PY
这两步做完再上传,能省掉大量「任务跑完发现谱图是空的」的往返。
§6 与库内资源的关系
6.1 关系图谱
GNPS 处在一组「质谱-代谢-结构」资源的中枢,看清它与其他资源的横向分工,比记字段更省事。
| 库内资源 | 与 GNPS 的关系 | 谁依赖谁 | 混用会出什么问题 |
|---|---|---|---|
| MassIVE | 底层数据仓,同一团队运营 | GNPS 分析读 MassIVE 的数据集 | 把 MSV 编号当 GNPS 任务号引用 |
| MetaboLights | 同领域研究存档,侧重研究级元数据 | 互不依赖,可互为外部验证 | 把研究编号当谱图编号查 |
| Metabolomics Workbench | 同领域数据仓,侧重于研究项目 | 互不依赖 | 两边的注释标准不同,直接合并会错位 |
| LOTUS | 天然产物结构-生物体映射库 | GNPS 谱图的注释结果可映射到 LOTUS 的结构 | 把 LOTUS 的结构当「GNPS 鉴定过」 |
| HMDB | 人类代谢物参考库 | 可作为补充库参与匹配 | 把 HMDB 编号当 GNPS 库谱编号 |
| ChEMBL | 生物活性库,含部分天然产物 | 无直接依赖 | 把活性数据与谱图注释混成一条结论 |
| PubChem 类结构源 | 结构参考 | 结构字符串的来源之一 | 结构可靠不等于谱图可匹配 |
常见误解是把它当成「天然产物版的 PubChem」:PubChem 以结构为主键,GNPS 以谱图为主键。
6.2 检索路径
从不同起点找一个东西,路径不一样。下面四条是最常用的。
第一条,从论文出发找数据。论文的数据可用性声明里通常有 MSV 编号或任务号,用编号直接进数据集页或结果页。
第二条,从化合物出发找谱图。走库谱检索,按化合物名或结构键查,命中后看等级与来源库,再决定是否采信。
第三条,从谱图出发找身份。把谱图转成通用标识,走解析入口,看它在公共数据里的命中情况,这是判断新颖度最快的方法。
第四条,从研究主题出发找数据集。走 MassIVE 检索接口,按标题与物种筛,再按文件数与创建时间排序,挑最可能相关的几个。
| 起点 | 入口 | 得到什么 | 下一步 |
|---|---|---|---|
| 一篇论文 | 数据集页或结果页 | 原始文件或网络结果 | 核对参数与阈值 |
| 一个化合物名 | 库谱检索 | 命中谱图与等级 | 看来源库与结构一致性 |
| 一张自己的谱图 | 通用标识解析 | 公共数据里的命中 | 按命中数判新颖度 |
| 一个研究主题 | 数据集检索接口 | MSV 编号列表 | 按文件数与时间排序 |
§7 质量评估与局限性
7.0 阅读本节前的一个前置校正
评分之前先纠正一个框架性误判:不要把 GNPS 的「准确率」与结构数据库的「准确率」放同一张表比。前者衡量谱是否相似,后者衡量结构判断是否正确,分子分母都不同。
正确的比法是分层比:库匹配层的命中可以按目标-诱饵法估错误率;网络传播层应报告边数与累计质量差,而不是一个笼统的准确率;从头预测层应报告候选排序的前 k 命中率。三层各自有各自的指标,混算即失效。
第二个前置校正关于「未命中」:库里没查到只等于没有它的参考谱,把未命中率当错误率会低估覆盖能力。
7.1 DAIMS 五维评分
按 DAIMS 框架的五个维度打分。分数只在内部可比,不跨数据集排名。
| 维度 | 分数 | 依据 | 扣分点 |
|---|---|---|---|
| 数据完整度 | 4.0 / 5 | 库、网络、仓三层齐备,谱图与元数据都有 | 结构覆盖率低,等级 4 至 5 的谱没有结构 |
| 可访问性 | 4.5 / 5 | 网页、JSON 接口、批量下载都开放,无需申请 | 大批量下载无官方打包,需自己拼 |
| 互操作性 | 4.0 / 5 | 支持 mzXML、mzML、MGF,通用谱图标识可跨平台 | 任务结果不可跨任务合并,编号体系三套 |
| 可复现性 | 3.0 / 5 | 任务号加参数可复现单次运行 | 平台版本迭代,旧任务的参数界面会变 |
| 注释可信度 | 2.5 / 5 | 有三级来源与五级分层,且有 FDR 估计工具 | 传播注释的误差会沿边累积,且不易察觉 |
综合下来大致落在可用的区间:拿它做线索发现、做语料构建是合适的;拿它做确证、做基准真值是不合适的。这个判断与 §1.5 的一句话判断一致。
7.2 三种注释来源的误差形态
误差形态取决于注释来源:库匹配是「查到错的东西」,网络传播是「位置对、身份错」,从头预测是「候选排错」。
| 来源 | 误差形态 | 典型场景 | 识别方法 |
|---|---|---|---|
| 库匹配 | 相似结构误命中 | 同系物、差一个甲基的类似物 | 看分数与匹配峰数,做诱饵对照 |
| 网络传播 | 位置对身份错 | 同分异构体、糖苷位置异构 | 数边数、算累计质量差 |
| 从头预测 | 候选排序不稳 | 对称结构、立体异构 | 看多工具交叉一致性 |
7.3 已知的、可枚举的偏差
第一类,链式簇假阳性。§4.3 的案例给了最小样本:簇呈链状时首尾的结构关系可能已经非常远,注释仍写成「某物的衍生物」。节点越多,长链越易形成。
第二类,低丰度离子丢失。折叠与阈值过滤优先保留强峰,含量低、离子化效率低的化合物峰数不足,既进不了库也连不上网,且偏向极性大、易在源内碎裂的类别。
第三类,仪器与能量异质。同一分子在高能碰撞与低能碰撞下谱图差异很大。跨实验室网络里,同一个化合物的谱图可能被拆到两个簇,看起来像两个不同分子。这类偏差在只看网络时几乎无法察觉,需要回到原始文件的碰撞能量字段核对。
第四类,库覆盖偏斜。库里的分布反映研究热点而非自然界分布,稀有物种与非常规化学类别几乎没有参考谱,形成「已知物越易发现、未知物越难认定」的马太效应。
第五类,同分异构体不可分。这是结构性的,不是参数能解决的。经典分子网络里,前体质量相同、碎裂主要峰相同的两个异构体,会被连成一条边。文献里常说的「同分异构体在网络中无法区分」,指的就是这一类。
第六类,模型偏好与结构偏好。从头预测工具对某些骨架表现好、对另一些表现差,而使用者往往只看到整体数字。按化学类别分层评估,才会发现偏差集中在哪。
7.4 外部验证矩阵
把不同来源的证据放在一起,才能判断某一层注释到什么程度可信。下表是一个验证思路的模板,不是针对某个具体化合物的结论。
| 证据类型 | 能证明什么 | 不能证明什么 | 成本 |
|---|---|---|---|
| 库匹配(等级 1) | 与标准品谱图一致 | 不能证明是同一批次样品中的同一物 | 低 |
| 保留时间与标准品一致 | 色谱行为一致 | 不能排除共流出 | 中,需标准品 |
| 网络位置与已知物相邻 | 结构相关 | 不能确定是哪一种相关 | 低 |
| 前体质量差可解释 | 修饰类型合理 | 不能排除其他组合 | 低 |
| 从头预测多工具一致 | 结构骨架可能正确 | 不能确定取代位置 | 中 |
| 核磁共振 | 结构确证 | 不能证明样品中丰度 | 高,需样品量 |
这张表的核心判断是:没有任何单一证据能到结构确证,只有多层证据叠加才行。平台提供的是前五行里的第一、三、四行,后两行必须由使用者自己做。
7.5 它为何能持续:把别人的硬盘变成公共基础设施
一个没有人工审核层的平台能活十年,靠的不是技术,而是三件事的耦合。
第一件是零成本贡献。一个实验室本来就要分析自己的数据,上传只是把分析挪到网页端,几乎不增加工作量。贡献的门槛低到接近零,才会有持续的数据流入。
第二件是即时的分析回报。上传者立刻拿到一张网络,这是他自己也要的东西。也就是说,贡献行为本身就是使用行为,平台不需要额外付酬。
第三件是引用的可计量性。平台有明确的引用方式与版本号,研究者能从被引里获得学术回报。这让「上传」从慈善行为变成可计入绩效的行为。
三件事叠成自足循环:数据越多、库越全、命中率越高、越多人传。脆弱点也清楚——命中率一降或分析一慢,正反馈就反向。
§8 生态位与历史
8.1 历史沿革
GNPS 的公开起点是 2016 年发表于 Nature Biotechnology 的论文,标题直译是「用全球天然产物社会分子网络共享与社区策展质谱数据」。核心主张三条:社区策展的库带来更好注释、数据驱动的社交网络促进协作、持续再分析让数据「活着」。
论文对问题背景的表述很直接:天然产物的化学多样性潜力未被充分开发,原因之一是天然产物库无法用原始数据检索,社区也没有除发表论文之外的共享方式。这句话点明了它的起点——不是技术不足,而是制度性缺位。
此后几轮演进:加入基于特征的分子网络(FBMN),让定量信息与谱图网络对齐;加入从头预测与注释传播工具链;从蛋白组学语境扩展到天然产物与代谢组学。
| 阶段 | 主要变化 | 对使用者的影响 |
|---|---|---|
| 2016 前后 | 平台公开,库匹配与经典网络成形 | 网络第一次成为公共工具 |
| 2017 至 2019 | FBMN 与离子身份网络加入 | 网络可以带定量,异构体部分可拆 |
| 2020 前后 | 注释传播与从头预测工具链整合 | 未命中谱图也有了候选 |
| 2022 之后 | 通用谱图标识与公共谱检索普及 | 单谱图可以跨平台引用 |
以上阶段划分依据官方文档的模块清单与论文的机制描述,具体年份未在官方页面逐项标注,标注为「未核实」。
8.2 它在生态位上的位置
按功能分,分子与组学领域有四种资源:结构库、研究存档、原始数据仓、分析平台。GNPS 是第四种的少数样本之一,而且它把前三种都咬合在同一套编号体系里。
| 资源类型 | 代表 | 回答的问题 | GNPS 的对应 |
|---|---|---|---|
| 结构库 | PubChem、LOTUS | 有哪些结构 | 库中结构字符串,覆盖窄 |
| 研究存档 | MetaboLights | 某项研究做了什么 | 任务与数据集,覆盖窄 |
| 原始数据仓 | MassIVE | 原始文件在哪 | 直接借用 |
| 分析平台 | GNPS 本身 | 这些谱图之间是什么关系 | 核心能力 |
这个位置带来一优一劣:优势是能把「谱图-关系-结构」串起来,劣势是必须同时承担三层的质量问题。
8.3 与相邻范式的分野
GNPS 的范式与传统专家策展库最根本的分野,在「谁有资格说这是什么」。
传统库里,资格是制度性的:评审委员会、标准品、同行评议、版本发布。一个化合物进库要经过一条明确的流程,速度慢但责任清晰。
GNPS 里,资格是统计性的:多少张独立的谱图把它连到了一起,多少条边支持它。速度快、覆盖广,但责任分散——平台只提供类比与分数,判断留给人。
这个分野没有绝对优劣,它取决于你要的是什么。要责任,走传统库;要覆盖,走 GNPS。要两者兼得,只能自己叠加工序。
8.4 谁在维护它
官方页脚标明版权归加州大学圣迭戈分校,版本号与最后修改日期都在持续更新。论文作者列表里有数十位来自不同机构的贡献者,说明这是一个跨机构协作的项目,而非单一实验室的产物。
资助指向美国国立卫生研究院与美国国家科学基金会,具体项目号未在首页列出,标注为未核实。这意味着它是公共资助的基础设施,没有付费档、没有服务水平协议、没有客服工单。
对使用者而言,这意味着三件事:服务中断时只能等;接口变更不会提前很久通知;出问题时只能靠文档与社区论坛。把这三条写进取数方案,比期待服务水平协议现实。
§9 使用指引
9.1 三种角色的路径
不同角色进入平台的入口完全不同,走错入口会浪费大量时间。
分析者(手上有一批自己采的数据)的路径是:格式转换、整理元数据表、网页端提交任务、读网络、按簇挑候选。最短的一次完整流程大约是这样的:把文件转成 mzML,写好两列的元数据表,选默认参数提交,等任务跑完,导出节点表与边表,按簇规模与库匹配情况筛出前几个值得追的簇。
使用者(只要现成的谱图或结果)的路径是:库谱批量下载或数据集检索,按可信度分层过滤,按需取峰表。这条路径没有提交环节,也没有等待,全部在数据接口上完成。
贡献者(要往库里加谱图)的路径是:先做一次分析任务,确认谱图质量,再把有结构信息的谱贡献进库,按等级要求准备元数据。贡献者的门槛比分析者高,因为库对结构信息有硬性要求。
| 角色 | 入口 | 关键动作 | 最容易卡住的地方 |
|---|---|---|---|
| 分析者 | 分子网络提交页 | 格式转换与元数据表 | 分组列没写,网络无法着色 |
| 使用者 | 库谱接口与数据集接口 | 分层过滤 | 字段类型不统一,解析报错 |
| 贡献者 | 库谱贡献页 | 结构与等级材料 | 等级 1 需要标准品与评议 |
9.2 一条最短的可用流程
从零到一张可读的网络是四步。下面这段把可自动化的部分串起来:清洗库谱、检索数据集、核对阈值。
import csv
import json
import urllib.parse
import urllib.request
LIB_URL = "https://external.gnps2.org/gnpslibraryjson"
DS_BASE = "https://massive.ucsd.edu/ProteoSAFe/QueryDatasets"
def fetch_json(url):
with urllib.request.urlopen(url, timeout=120) as resp:
return json.loads(resp.read().decode("utf-8", errors="replace"))
def library_stats(rows):
#-- 按可信度等级分组计数,先看清库的结构再决定用哪一层
stats = {}
for r in rows:
cls = str(r.get("Library_Class") or "").strip()
stats[cls] = stats.get(cls, 0) + 1
return stats
def datasets_total():
params = {"pageSize": 1, "offset": 0, "query": "{}"}
url = DS_BASE + "?" + urllib.parse.urlencode(params)
d = fetch_json(url)
return int(d.get("total_rows", 0))
def cluster_edges(edge_path, min_cos=0.7):
#-- 边表里可能含低于阈值的行,统计簇规模前先按阈值裁一遍
keep = []
with open(edge_path, newline="", encoding="utf-8") as f:
for row in csv.DictReader(f, delimiter="\t"):
if float(row["Cosine"]) >= min_cos:
keep.append(row)
return keep
lib = fetch_json(LIB_URL)
print("library rows:", len(lib))
print("by class:", library_stats(lib))
print("massive public datasets:", datasets_total())
四步的完整流程是:转换谱图格式、写元数据表、在网页端提交分子网络任务、导出节点表与边表后运行上面这段脚本核对阈值。前三步不可自动化,第四步可以。
9.3 引用方式
官方给出的引用是 2016 年那篇论文:Mingxun Wang 为第一作者,卷 34、期 8、页 828 至 837,DOI 10.1038/nbt.3597,PubMed 号 27504778。数据可用性声明建议同时给出论文引用、数据集或任务编号、访问日期。
具体到某一张谱图,引用格式应含库谱编号或通用谱图标识;只写「数据来自 GNPS」无法定位证据。
引用字段的完整说明见附录 C。
§10 AI 使用声明
| 项目 | 说明 |
|---|---|
| 模型参与范围 | 结构梳理、文字组织、代码示例编写 |
| 事实来源 | 官方主站、官方文档站、官方接口返回值、2016 年论文摘要 |
| 数字口径 | 规模与结构数字来自上述来源,标注页面层级 |
| 未核实内容 | 历史阶段的具体年份、资助项目编号、库谱总数的权威口径 |
| 案例性质 | §4.3 案例为教学性构造,步骤可在平台复现 |
| 代码验证 | 示例代码按接口字段写就,未在本次运行中逐条执行 |
| 不该由模型负责的部分 | 具体化合物的结构判断、参数调优的最终选择 |
| 建议的人工复核 | 引用任何注释前,回查库谱等级与网络边数 |
常见误读(避坑清单)
| 说法 | 实际 | 证据 |
|---|---|---|
| 网络里连成一簇就是同一个分子 | 簇只说明碎裂相似,同分异构体、同系物、相似骨架都会同簇 | 官方文档的分子网络理论页明确写了修饰相关的相似性限制 |
| 分子网络能鉴定结构 | 它给关联与候选,结构要靠库匹配、标准品或从头预测 | 官方词汇表把网络定义为相似度计算的网络,注释另有来源 |
| GNPS 就是 MassIVE | 两者职责不同,一个做分析一个存文件 | 官方 FAQ 明确区分原始数据与库谱 |
| 上传的谱图默认公开 | 分析与数据集默认私有,公开是显式动作 | 官方 FAQ 的数据隐私一节 |
| 库里的谱都是标准品测的 | 库按五级分层,只有 1 级接近标准品条件 | 库谱记录的 Library_Class 字段 |
| 传播注释与库匹配一样可信 | 传播是按距离推理,误差沿边累积 | §4.3 的案例逐行给出边数与量差 |
| 未命中说明分子不存在 | 只说明库里没有参考谱 | 库覆盖受历史研究热点影响,见 §7.3 |
| 网络节点数就是样品数 | 节点是谱图,一个样品可贡献多个节点 | 节点表以扫描为单位,见 §2.2 |
| 同一化合物的谱图必在同一簇 | 仪器与碰撞能量差异会把它们拆开 | 官方文档关于相似性依赖实验条件的表述 |
FAQ
Q1:分子网络里同一个簇的谱图能直接当成同一个分子吗?
不能。簇只说明这些谱图的碎裂模式足够相似。同分异构体、同系物、甚至碰撞能量接近的不同化合物都可能落进同一簇。要落到结构,必须另做库匹配、标准品比对或从头预测。
Q2:GNPS 和 MassIVE 是同一个东西吗?
不是。MassIVE 存原始数据,按数据集组织,给 MSV 编号;GNPS 在上面做比对、成网、库匹配和注释传播,按分析任务组织,给 32 位任务号。同一团队运营,职责不同。
Q3:我上传的谱图会自动变成公开库吗?
不会。分析任务默认私有,只有把单个注释谱图贡献进库,或者把整个 MassIVE 数据集设为公开,数据才对外可见。公开是显式动作,不是默认结果。
Q4:库匹配和网络传播哪个更可信?
库匹配更可信,因为它是查表,有参考谱图与结构支撑。网络传播是推理,依据是邻居被匹配上了,误差会沿边累积。两者必须分开统计,不能混在一个准确率里。
Q5:GNPS 能区分同分异构体吗?
在经典分子网络里基本不能,因为两者前体质量与碎裂峰常常高度一致。离子淌度数据加上离子身份网络可以在一定程度上拆开,但需要额外的采集维度,不是默认能力。
Q6:默认参数能直接用吗?
多数情况下可以,余弦 0.7 与最少匹配峰 6 是先验经验值。但如果你的样品集中在某个化学类别,或者仪器是低分辨,建议先用小批数据试参数,看簇的形态是否合理,再跑全量。
Q7:平台能处理 GC-MS 数据吗?
能,走单独的 GC-MS 通道,先把 EI 谱去卷积成纯谱,再建网络。注意 GC-MS 的碎裂由电子轰击产生,与 LC-MS 的碰撞诱导解离机制不同,两边的谱图不能混在一张网络里。
Q8:库谱能下多少?
可以批量下载全部公开库谱的 JSON,含峰表与结构字符串。文件体量较大,建议用流式读取或分批取。具体条数以官方接口的返回行数为准,本文不引用未经权威确认的总数。
Q9:任务的编号怎么引用?
用 32 位任务号,并给出完整结果页网址。任务号只在这一次运行内有效,参数改了就要重跑重取。论文的方法部分建议同时写出关键参数与阈值。
Q10:谱图可以商用吗?
许可由提交者选择,多数是 CC0 或 CC BY,但库是多家来源的并集,个别谱图可能带不同条款。商用前应逐条查看来源与许可,不能以平台的总体描述替代逐条核对。
Q11:为什么我自己采的同一化合物,谱图连不上任何簇?
最常见的原因有三个:碰撞能量与库谱差距大、前体离子选取有偏差、以及峰数太少过不了最少匹配峰的门槛。先核对这三个,再考虑参数。
Q12:它适合用来做监督学习的标签吗?
可以,但要分层使用。库匹配且等级 1 至 2 的谱图适合当高置信标签,网络传播结果只能当弱标签或伪标签,从头预测结果只能当候选集合。三层混在一起训练,模型会学到一个无法解释的中间态。
术语表
| 术语 | 英文 | 含义 |
|---|---|---|
| 分子网络 | molecular networking | 把谱图当节点、相似度当边构成的图 |
| 经典分子网络 | classical molecular networking | 只在谱图层建网,不接特征表 |
| 基于特征的分子网络 | FBMN | 接上特征检测与对齐结果,带定量信息 |
| 修正余弦 | modified cosine | 允许前体质量偏移的谱图相似度打分 |
| 余弦分数 | cosine score | 归一化点积,1 为完全相同 |
| 谱图聚类 | MS-Cluster | 把同前体质量的近重复谱折叠为代表谱 |
| 代表谱 | consensus spectrum | 折叠后用于建网的那张谱 |
| 分子家族 | molecular family | 网络中互相连通的一组谱图 |
| 连通分量 | connected component | 图论意义上的最大连通子图 |
| 互近邻过滤 | neighbor top K | 只保留彼此互认靠前的边 |
| 连通分量上限 | connected component max size | 超过就切除最低分边以碎裂巨簇 |
| 前体质量差 | delta m/z | 两个相连节点的前体质量差,对应修饰 |
| 离子身份网络 | ion identity networking | 用峰形相关补加边的网络 |
| 库匹配 | spectral library search | 与参考谱比对的查表过程 |
| 注释传播 | network annotation propagation | 把库匹配结果沿网络扩散给邻居 |
| 从头预测 | de novo annotation | 不依赖参考谱的候选生成 |
| 去重复 | dereplication | 快速识别已知物以聚焦新分子 |
| 通用谱图标识 | USI | 跨平台定位单张谱图的字符串 |
| 目标-诱饵 | target-decoy | 估算匹配错误率的对照设计 |
| 活数据 | living data | 发表后仍被持续再分析的数据 |
| 可信度等级 | library class | 库谱的 1 至 5 级证据强度分级 |
| 质荷比 | m/z | 质量除以电荷,谱图的横轴 |
| 碰撞能量 | collision energy | 碎裂强度参数,影响谱图形态 |
| 加合物 | adduct | 离子化时附着的离子形式,如 M+H |
附录 A:核心数字核对表
| 项 | 值 | 来源 | 来源层级 |
|---|---|---|---|
| 公开数据集总数 | 两万余个(本次查询 total_rows 为 20451) | MassIVE 检索接口 | 官方接口 |
| GNPS 语境下的数据集入口 | 1000+ | 主站首页入口说明 | 官方页面 |
| 网络建边默认余弦阈值 | 0.7 | 官方文档分子网络理论页 | 官方文档 |
| 最少匹配峰数 | 6 | 官方文档分子网络理论页 | 官方文档 |
| 连通分量默认上限 | 100 个节点 | 官方文档分子网络理论页 | 官方文档 |
| 库可信度分层 | 1 至 5 级 | 库谱记录字段 | 官方接口 |
| 输入谱图格式 | mzXML、mzML、MGF | 官方文档分子网络页 | 官方文档 |
| 平台版本号 | 1.3.16 | 主站页脚 | 官方页面 |
| 页面最后修改 | 2026-10-23 | 主站页脚 | 官方页面 |
| 主论文卷期页 | 34(8):828-837 | Europe PMC 记录 | 论文摘要 |
| 主论文 DOI | 10.1038/nbt.3597 | Europe PMC 记录 | 论文摘要 |
| 主论文 PubMed 号 | 27504778 | 主站引用区与 Europe PMC | 官方页面加论文 |
| 库谱编号格式 | CCMSLIB 加 11 位 | 库谱记录 | 官方接口 |
| 任务号格式 | 32 位十六进制 | 官方 FAQ | 官方文档 |
附录 B:数字的来源分层
第一层,官方页面与官方接口。 公开数据集总数、版本号、最后修改日期、库谱字段与分层、编号格式,均来自主站、文档站或接口返回值。这类数字有明确的抓取时点,跨月引用会漂移。
第二层,论文摘要。 主论文的卷期页、DOI、PubMed 号、以及三条核心主张(社区策展、数据驱动社交网络、活数据),来自 Europe PMC 的记录。论文全文在本环境不可取,机制描述以官方文档为准。
第三层,未核实。 库谱总数、历史阶段的具体年份、资助项目编号、跨实验室提交者的地域分布,均未在本次研究中获得权威口径,正文中凡涉及处已标注或改用概数。
三层的使用原则是:第一层可以直接写进表格,第二层用于支撑机制与引用,第三层只能作为背景,不能作为结论依据。
附录 C:完整参考文献
- Wang M, Carver JJ, Phelan VV, Sanchez LM, Garg N, Peng Y, et al. Sharing and community curation of mass spectrometry data with Global Natural Products Social Molecular Networking. Nature Biotechnology, 2016, 34(8): 828-837. DOI: 10.1038/nbt.3597. PMID: 27504778.
- GNPS 主站. https://gnps.ucsd.edu/ ,页脚版本 1.3.16,最后修改 2026-10-23,访问日期 2026-10-26.
- GNPS 文档站. https://ccms-ucsd.github.io/GNPSDocumentation/ ,分子网络理论页、词汇表页、API 页、FAQ 页,访问日期 2026-10-26.
- GNPS 库谱批量接口. https://external.gnps2.org/gnpslibraryjson ,访问日期 2026-10-26.
- MassIVE 数据集检索接口. https://massive.ucsd.edu/ProteoSAFe/QueryDatasets ,访问日期 2026-10-26.
- Europe PMC 检索接口. https://www.ebi.ac.uk/[europepmc](https://www.qianfanghub.com/ai-ready-dataset/europepmc/1353)/webservices/rest/search ,访问日期 2026-10-26.
附录 D:常见任务的代码索引
| 任务 | 用哪段代码 | 关键参数 | 注意 |
|---|---|---|---|
| 下载并清洗库谱 | §5.2 的两段函数 | 最少峰数、等级上限 | 峰表是字符串,要二次解析 |
| 检索数据集 | §5.3 的分页函数 | 页大小、页码 | 总量字段是仓口径 |
| 读网络结果 | §5.4 的读表函数 | 余弦阈值 | 先按阈值裁边再统计 |
| 解析单谱图 | §5.5 的解析函数 | 通用标识字符串 | 标识内含冒号,要整体编码 |
| 一次跑通全流程 | §9.2 的汇总脚本 | 无 | 只覆盖可自动化部分 |
附录 E:如果只记五件事
- 它标注的是谱图之间的关系,不是分子的身份。
- 聚成一簇只证明碎裂相似,不证明结构相同。
- 注释有三种来源,可信度差一个量级,报告时必须分开写。
- 库按 1 至 5 级分层,等级是证据强度,不是质量分。
- 它会持续存在,因为上传与分析是同一个动作,贡献者立刻拿到回报。
编辑说明
本文的数字核验时间为 2026-10-26,核验方式为直接访问主站页面、文档站页面与两个官方接口,并以 Europe PMC 记录核对主论文的卷期页与标识符。以下内容未覆盖:库谱总数的权威口径、历次版本变更的具体年份、资助项目编号、提交者的地域分布统计。凡正文中出现「未核实」之处,均属未取得权威来源,非刻意回避。
示例代码按官方接口的字段形态编写,覆盖字段清洗、分页检索、表读取与单谱图解析四类常见任务。代码中的谱图标识与数据集编号取自公开文档示例,用于说明拼接规则,不代表对任何具体数据集的推荐。§4.3 的案例为教学性构造,其每一步操作都能在平台上复现,但不对应任何已发表结论。
关于价值判断的起点:本文认为分子网络的正确定位是「线索生成」,把它当「结论生成」使用是主要风险来源。这一判断基于官方文档对网络的定义与注释来源的划分,不涉及对平台运营方的评价。
相关数据集导航
以下为站内 AI-Ready 数据集百科中与本词条共享多个主题标签的相关数据集,按相关度降序排列:
- hmdb — 共享标签:基因组学与多组学 / 药物发现与化学 / 代谢组学
- intact — 共享标签:基因组学与多组学 / 药物发现与化学
- msigdb — 共享标签:基因组学与多组学 / 药物发现与化学
- lipid-maps — 共享标签:基因组学与多组学 / 药物发现与化学
- intenz — 共享标签:基因组学与多组学 / 药物发现与化学
- alphafold — 共享标签:基因组学与多组学 / 药物发现与化学
- pride — 共享标签:基因组学与多组学 / 代谢组学
- proteomexchange — 共享标签:基因组学与多组学 / 代谢组学
- disgenet — 共享标签:基因组学与多组学 / 药物发现与化学
- open-targets — 共享标签:基因组学与多组学 / 药物发现与化学
导航说明:本章节由全站统一标签体系自动计算生成(标签重合度算法),双向可达;点击链接可跳转至对应数据集词条。

