原文地址:https://itxiaozhang.com/parse-hmdb-xml-extract-compounds-to-csv
如果您需要远程电脑维修或者编程开发,请加我微信咨询。
需求分析#
在使用安捷伦 MassHunter 分析软件进行数据处理时,需要使用 HMDB 数据库中的化合物信息作为分析数据来源。
HMDB 官方提供的数据为 XML 格式文件,文件体积约 845 MB,解压后包含 65000 多条化合物记录。该数据结构无法直接用于分析软件,同时部分分析所需字段未以结构化方式提供,需要进行数据整理与提取。
为满足分析需求,需要从 XML 文件中提取有效化合物数据,并整理为结构化表格格式。目标数据需包含以下字段:
- HMDB ID
- 化合物名称(Name)
- 分子式(Formula)
- 质量(Mass)
- SMILES
- 保留时间(Retention Time)
- 二级质谱信息(MS/MS)
由于原始 XML 数据量较大,人工整理不可行,因此需要通过程序自动解析 XML 文件,提取符合要求的化合物记录,并补充所需字段信息。
最终需要将整理后的数据输出为 CSV 文件,形成标准化数据表,以便在分析软件中进行后续数据处理与分析。
需要注意的是,同一化合物可能对应不同的质谱信息或属性,因此在结果数据中可能出现名称相同但属性不同的多条记录,这属于正常情况。
开始实现#
1. 下载 HMDB XML 数据文件#
从 HMDB 数据库下载完整数据包,获取约 845 MB 的 XML 文件。
下载完成后进行解压,得到包含约 65000 多条化合物数据的 XML 文件。
2. 解析 XML 文件#
对 XML 文件进行解析,读取其中的化合物节点信息,并提取有效数据记录。
重点提取以下字段:
- HMDB ID
- Name(名称)
- Formula(分子式)
- Mass(质量)
- SMILES
- Retention Time(保留时间)
- MS/MS(二级质谱信息)
解析过程中需要过滤无效或缺失关键字段的记录。
3. 数据整理与字段补充#
将解析得到的化合物信息进行结构化整理:
- 按字段整理为统一的数据表结构
- 对缺失字段进行补充或统一格式
- 保证所有记录字段完整
需要注意:
- 同一化合物可能存在多条记录
- 不同记录对应不同的质谱或属性信息
- 因此结果中出现名称重复属于正常情况
4. 生成 CSV 数据文件#
将整理后的化合物数据导出为 CSV 文件。
CSV 文件包含以下列:
- HMDB ID
- Name
- Formula
- Mass
- SMILES
- Retention Time
- MS/MS
最终生成的文件数据量约 65000 条记录,可直接用于后续分析软件的数据导入或处理。
部分代码#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
| import os
import csv
import glob
def load_metabolite_dict(xml_path):
raise NotImplementedError
def parse_msms_file(path, meta_dict):
raise NotImplementedError
def main():
base_dir = os.path.abspath(os.path.join(os.path.dirname(__file__), ".."))
metabolites_xml = os.path.join(base_dir, "hmdb_metabolites", "hmdb_metabolites.xml")
spectra_dir = os.path.join(base_dir, "hmdb_experimental_msms_spectra")
output_dir = os.path.join(base_dir, "output")
out_csv = os.path.join(output_dir, "hmdb_msms_full_enriched.csv")
os.makedirs(output_dir, exist_ok=True)
meta_dict = load_metabolite_dict(metabolites_xml)
files = sorted(glob.glob(os.path.join(spectra_dir, "*.xml")))
header = [
"hmdb_id", "name", "formula", "mass", "smiles",
"rt_value", "rt_unit", "polarity", "collision_energy",
"instrument", "peaks", "source_file"
]
with open(out_csv, "w", newline="", encoding="utf-8-sig") as fp:
writer = csv.DictWriter(fp, fieldnames=header, extrasaction="ignore")
writer.writeheader()
for f in files:
rec = parse_msms_file(f, meta_dict)
if rec:
writer.writerow(rec)
if __name__ == "__main__":
main()
|
视频版本#