2.1.1 分子是一张标注图:节点、边与属性
1.2 节把分子的机器表示分成字符串、指纹与图三种面貌。三者之中,图最接近化学家的结构式:原子对应节点(node),化学键对应边(edge)。记分子图(molecular graph)为 G=(V, E),V 是原子集合,E 是键集合。裸的图论结构只回答"谁连着谁";化学信息几乎全部存放在标注里——节点与边各自携带一束属性。连接方式本身就携带结构信息:乙醇与二甲醚的重原子集合同为 {C, C, O},前者的边是 C–C 与 C–O,后者是 C–O 与 C–O,同分异构在图上就是两张不同的图。
节点属性至少包括:元素(原子序数)、同位素质量数、形式电荷(formal charge)、手性标签、隐式氢计数,以及由前几项推导的杂化态、环隶属与芳香标记。边属性包括:键级(bond order)(单键、双键、三键、芳香键)、是否共轭、是否在环上。这些属性并不平权:元素与键级参与价态检查和芳构化判定;电荷与手性决定电性描述符与立体化学;杂化态与共轭标记则是 sanitize 阶段由前两者推导出的"二级属性"(见 2.1.4)。
键级的取值里藏着一个表示论难题:苯怎么写。单双键交替的凯库勒表示(Kekulé representation)忠实于定域键图景,却让本来完全等价的六条边在数据上不再等价;把六个原子与六条边整体标记为芳香,恢复了对称,又丢掉"双键画在哪"的信息。两种表示可以互相转换:凯库勒化(kekulization)为芳香体系指派一套合法的交替单双键,芳构化感知(aromaticity perception)反过来识别满足芳香判据的环系并折叠成芳香标记。RDKit 的选择是兼收并蓄:Mol 对象中键的键级字段与芳香标记字段并存,sanitize 时先验证凯库勒化可行、再设置芳香标记,需要时随时往返(Weininger, 1988;Landrum et al., 2026)。
那么分子图是图论意义上的多重图(multigraph)——允许两点间平行边——吗?化学键的语义给出否定回答:两原子之间的 σ 骨架至多一条,"双键""三键"是同一条边的键级取值,不是两条边。RDKit 据此规定两原子间至多一条边,重复连边在构建阶段即报错。真正的"多重"只出现在 π 体系的表示选择里:凯库勒式的双键与芳香式的单边,是同一化学事实的两种编码。本教材此后说"分子图",指的都是这种无平行边、无自环、属性丰富的标注图(labeled graph)。
标注图与多重图。图 G=(V, E) 若为每个节点、每条边指定属性函数 ℓV: V→AV、ℓE: E→AE,称为标注图;若允许两点间有多条平行边或自环,称为多重图。分子图是属性取值受化合价规则约束的标注图:两原子间至多一条边,自环不存在,平行边由键级属性吸收。
2.1.2 机内存储:稀疏邻接表而非邻接矩阵
图有两种经典存法:稠密的邻接矩阵(adjacency matrix)——V×V 矩阵,第 i 行 j 列为 1 表示原子 i 与 j 相邻;稀疏的邻接表(adjacency list)——每个节点维护一张邻居清单,每条边只存一份。药物分子的规模直接决定取舍:重原子数 V 多在 10–60 之间(类药性的经验上界约 50),边数 E 受价数刚性约束。
代入数字更直观。V=30 的中等分子,邻接矩阵要 900 格,非零元只有 2E ≈ 66 个,九成以上是零;邻接表只存 30 张清单、共 2E 个条目。稀疏性不是偶然,而是分子图的本质先验——抓住它,存储成本就从平方级降到线性级:
化学键没有方向,这带来一个实现细节:无向边的双向索引。每条边在两端原子的邻居清单里各放一个指向同一边对象的引用,边的本体——键级、共轭标记等属性——只存一份。如此"查某原子的邻居"沿清单走,"查某条边连着谁"读边对象即可,两侧都是常数或与度成正比的代价。
RDKit 的做法。键(Bond)对象记录起止原子编号,原子(Atom)对象持有邻居原子与邻居键的引用表,两边共享同一批对象;增删原子或键时同步维护两端。这套结构与"节点属性表 + 边表 + 双向索引"的抽象一一对应,也是第 3 章消息传递沿邻接表传播的物理载体。
当然,稀疏并非处处占优。V=3 的乙醇,矩阵 9 格、邻接表 7 项,差距可以忽略,小图上矩阵的访问简单与内存连续反而占优。化学信息学工具仍选邻接表,服务的是"分子会大到大图"的场景:真实数据集里混着二十个重原子的小片段与上百个重原子的多肽样分子,存储结构必须按上界设计,而不是按平均值设计。
邻接矩阵并非无用。第 3 章的图卷积里,邻接矩阵 A 与度矩阵 D 的组合是消息传递的代数语言;只是那里的 A 同样以稀疏格式存放,思想与邻接表一致。区别在视角,不在本质:矩阵便于推导,邻接表便于存储。
习题 2.1-1
设某稠环体系重原子图 V = 50、E = 100。(1) 分别计算邻接表与邻接矩阵的存储条目数(邻接表含 V 张清单、共 2E 个邻居条目;矩阵 V² 格),并给出比值。(2) 由度和恒等式计算平均度,说明该图处于何种化学情形,对照典型药物分子又如何。
参考解答(1) 邻接表 = V + 2E = 50 + 200 = 250 项;邻接矩阵 = 50² = 2500 格,是前者的十倍;比值 V²/(V+2E) 随 V 增大而增大,稀疏优势更明显(若每格与每项还要存键级,比例不变)。(2) 平均度 = 2E/V = 4,恰达四价上界(式 2.1-1 取等号):全部原子都是无氢的四价重原子,如深稠合的多环芳烃碎片。典型药物分子平均度约 2.1–2.2、E ≈ 1.1V,远比此稀疏,邻接表的差距只会更大。
2.1.3 隐式氢与显式氢:省略的艺术
有机分子里氢常占原子数一半以上,但与碳相连的氢数目几乎总能由价规则唯一推出:碳四价、度 2、无电荷,则氢数必为 2。可推导的信息不必存储。RDKit 默认把这类氢折叠为原子的一个计数值,图里只保留重原子,称为隐式氢(implicit hydrogen);为每个氢建立真实节点,则称显式氢(explicit hydrogen),需要时再补。折叠的依据是一条一步算式:
省略的收益有三重:图更小(乙醇 3 个节点对 9 个);子结构匹配的模式不必逐个列举氢,2.3 节的 SMARTS 直接作用于重原子图;二维布局与画图不受成串氢的干扰。分子量、分子式这类整体量照常把隐式氢计入——信息没有丢,只是换了存放位置,从节点挪到了属性。
有些场合必须显式。pKa 与质子化状态的精细计算要区分羟基上那一个氢的得失;力场与构象优化需要氢的坐标,否则无以谈氢键几何与范德华接触;三维描述符同理;氘、氚这类同位素氢无法折叠为普通计数,指定立体化学所需的氢也须保留。从语义上讲,补氢(AddHs)是在图上新增节点并按价规则连接,去氢(RemoveHs)把"可折叠"的氢重新折回属性——带同位素、带电荷或承担立体化学定义的氢不在折叠之列,这是保护信息,不是遗漏。
氢的口径影响下游。同一分子在重原子图与全原子图下的节点数、节点特征分布都不同。DeepChem 与 TorchDrug 的特征化器对氢的策略并不一致:有的显式补齐,有的只用重原子。跨框架比较模型、或拼接两套特征时,先统一氢的口径,否则"模型差异"里混入了"表示差异"。分子量等整体描述符不受影响,图神经网络学到的逐原子表示则随口径改变。
2.1.4 化合价检查与 sanitize 流程
任意一张标注图未必对应真实分子:五条键的碳、三个重邻居的氧,化学里不存在。把"图"与"合法分子"区分开的,是化合价规则(valence rules)。主族元素的常见价上限有表可查(表 2.1-1);形式电荷会移动允许区间——氮带一个正电荷可取四价(季铵盐),氧带负电荷降为一价(醇盐),带正电荷的氧可取三价(水合氢离子)。判定方法是把原子所有键的键级求和(双键计 2、芳香键计 1),与该元素在当前电荷下的允许价比较。
| 元素 | 默认允许价 | 电荷修正(示例) |
|---|---|---|
| H | 1 | — |
| B | 3 | — |
| C | 4 | 无修正:五价碳不存在 |
| N | 3 | +1 电荷升至 4,如季铵 [N+](C)(C)(C)C |
| O | 2 | −1 降至 1(醇盐 [O−]);+1 升至 3([OH3+]) |
| F, Cl, Br, I | 1 | −1 时 0 价(卤阴离子 [Cl−]) |
| Si | 4 | — |
| P | 3, 5 | 五价磷如磷酸 P(=O)(O)(O)O |
| S | 2, 4, 6 | 六价硫如硫酸 S(=O)(=O)(O)O |
| 过渡金属 | 无默认上限 | 价态由氧化态与配位环境决定,默认不检查 |
从 SMILES 或 MolBlock 解析出的图只是初步拓扑;结构清洗(sanitization)——常直接称 sanitize——是一串按序执行的检查与推导,任何一步失败即整体失败。按 RDKit 文档的次序(Landrum et al., 2026):
第一步,价态计算。逐原子求显式价与隐式氢数,超价在此抛出异常——五键碳 C(C)(C)(C)(C)C 被拒,正是在这一步。第二步,结构清理与环感知。修正硝基等少数非标准写法;找出最小环集(smallest set of smallest rings, SSSR),为每个原子与键标记环隶属。第三步,凯库勒化与共轭、杂化感知。为芳香环系指派交替单双键,指派不出的"芳香声明"是假芳香,报错;随后沿单双交替路径标记共轭键,推断各原子的 sp/sp²/sp³。第四步,芳构化感知。按判据把满足条件的环系折叠回芳香标记,恢复对称表示。第五步,立体化学指派与隐式氢调整。由邻接与手性标签定出立体中心的构型,落定各原子的隐式氢计数。每一步都在为后续计算生产缓存:环信息供指纹与描述符取用,共轭标记影响量子相关描述符,杂化态决定力场参数的选择。
价态计算中芳香键按 1 计,值得用一个例子说明。苯环上的碳连着两条芳香键与一条指向取代基的单键,键级和为 3,低于碳的允许价 4,于是隐式氢数取 1——这与化学直觉一致:取代苯的环碳恰好带一个氢。若按"一条芳香键计 1.5"的电子计数口径,会得出同样的氢数,但中间量不同;RDKit 在存储与价态检查上取整数口径,电子计数只在芳构化判据内部出现。两种口径并存不矛盾,各自服务于不同的推导目标。
为什么非法分子必须尽早抛错?sanitize 之后的每一步——指纹、描述符、构象生成、画图——都默认图化学自洽。一个五价碳会让隐式氢数算出负值,芳构化在残缺的 π 电子计数上连锁失败;指纹函数遇到残缺的缓存,仍会吐出一串看似合法的数字。入口处不拦截,错误就改头换面混进训练集,以"特征值略怪"的面目出现,事后无从追溯。早失败(early failure)把数据问题留在数据阶段,是整条流水线可靠的起点。
静默吞掉失败更危险。常见反模式:解析循环里 except: pass,失败分子记为 None 或直接跳过。若失败并非随机,而是集中在某类结构(金属有机、高价硫、新奇骨架),训练集与测试集的分布便悄悄分叉,指标虚高而不自知。更隐蔽的是主动绕过:sanitize=False 能让任何图通过解析,五价碳也照单全收。正确做法是记录失败清单与失败率,人工抽查失败原因,再决定修复或剔除——2.6 节的清洗工序正为此设。
整条流水线串起来看(图 2.1-2):每一步既做检查、又生产后续要用的缓存;任何一步抛错,整个分子都不被放行。步骤的次序不可调换——环感知依赖干净的价态,凯库勒化依赖环信息,芳构化感知依赖凯库勒化的验证结果,立体化学指派依赖前述全部标记。
下面两段代码印证上述机制:第一段查看属性挂在何处,第二段复现价态拦截的位置。
from rdkit import Chem
mol = Chem.MolFromSmiles("CCO") # 解析并默认完成 sanitize
a = mol.GetAtomWithIdx(1) # 原子即节点:属性挂在节点上
print(a.GetSymbol(), a.GetTotalNumHs(), a.GetHybridization())
# C 2 SP3 —— 三个氢不在图里,是"隐式氢计数 + 杂化态"两个节点属性
b = mol.GetBondBetweenAtoms(1, 2) # 键即边:键级是边的属性
print(b.GetBondType(), b.GetIsConjugated())
# SINGLE False
bad = Chem.MolFromSmiles("C(C)(C)(C)(C)C") # 五键碳:清洗抛错,返回 None
raw = Chem.MolFromSmiles("C(C)(C)(C)(C)C", sanitize=False)
print(raw.GetNumAtoms()) # 6 —— 不做价态检查,图照常建成
Chem.SanitizeMol(raw) # 此处抛 AtomValenceException:
# Explicit valence ... C, 5, is greater than permitted
习题 2.1-2
判断下列 SMILES 片段能否通过 RDKit 价态检查,并给出理由(双键按 2 计、芳香键按 1 计):① C(C)(C)(C)(C)C;② [N+](C)(C)(C)C;③ O(C)(C)(C);④ S(=O)(=O)(O)O。
参考解答① 中心碳五条单键,总键级 5 > 4,且碳无电荷修正,非法。② 氮四条单键总键级 4,默认允许价 3,但 +1 电荷把允许价升至 4,恰达上限,合法(季铵盐)。③ 氧三条单键总键级 3 > 2,无电荷修正,非法。④ 硫的键级和 = 2+2+1+1 = 6,硫允许价含 6,合法(硫酸)。规律:先按表 2.1-1 查允许价,再按电荷上下移动区间,最后比较键级和。
习题 2.1-3
苯的两种写法 C1=CC=CC=C1 与 c1ccccc1,解析并 sanitize 后得到的内部图为何可以一致?从"凯库勒化与芳构化感知互为逆操作"出发,说明两步各自保证什么,并解释为何两种写法会给出同一套分子指纹。
参考解答凯库勒化把芳香标记展开为一组合法的交替单双键,其可行性验证了环上 π 电子确能定域指派;芳构化感知把满足芳香判据的交替环系折叠回统一的芳香标记。两步共享同一判据,故无论输入采用哪种写法,sanitize 结束时都收敛到同一内部态:六个芳香原子标记加六条芳香边。指纹读取的是 sanitize 之后的缓存属性,与输入写法无关,故同一(指纹还依赖规范化次序与哈希参数,2.5 节展开)。往返一致性由此成为工程保证:表示可以换,化学不丢失。
2.1.5 Mol 对象的两态生命周期
Mol 对象的一生分两态。可编辑态(editable state)(RDKit 的 RWMol):原子与键可增可删,属性缓存不作数;片段拼装、模板反应、逐原子搭骨架都在这一态操作,图允许暂时不满足价规则——先把骨架连完,再回头补电荷与氢。已清洗态(sanitized state):通过 sanitize 之后,图带上整套推导缓存,分子指纹、描述符、画图、构象生成都以这一态为前提。两态之间靠显式转换衔接:编辑完成即清洗冻结,需要再改则解冻回可编辑态。
直接改动已清洗的分子会留下隐患:缓存还停留在旧图上,环信息与共轭标记可能与当前图不一致。因此改图之后必须重新清洗(或显式更新缓存),这是使用约定,更是正确性约定。生命周期的要义可以概括为"编辑—验证—冻结":冻结态上的一切只读计算,都以验证通过为前提。
这套状态机也解开一个常见疑惑:为什么"从 SMILES 建分子"有时得到 None。解析函数把解析与清洗一次完成,清洗抛错时对象连同异常一起被收走,调用方拿到空值——错误不发生在"使用时",而发生在构建时,即上节第二段代码所示。两态的转换关系见图 2.1-3。
2.1.6 MolBlock 与 SDF:图的文本化身
内存中的 Mol 对象无法直接落盘或传输,需要文本序列化。MDL MolBlock 是事实标准之一(Dalby et al., 1992):首部是计数行(counts line),给出原子数与键数及版本;随后原子块(atom block)每原子一行——三个坐标、元素符号,再接一串属性列(质量差、电荷码、立体标记等);键块(bond block)每键一行——两端原子编号、键型代码(1 为单键、2 为双键、4 为芳香键)。V2000 计数行只有三位数宽,最多 999 个原子,超出或需表达复杂特性时用 V3000。原子块、键块与 2.1.2 的节点表、边表一一对应:MolBlock 就是 Mol 对象逐行铺开的文本形态。
SDF(Structure-Data File) 在 MolBlock 之后追加数据字段——字段名与取值各成片段——以独占一行的 $$$$ 结束一条记录,由此容纳成千上万个分子及其标注性质。它既是文件格式,也是数据集容器,MoleculeNet 的不少数据集以此分发。与 SMILES 相比:SMILES 是不含坐标的一维串,胜在紧凑(Weininger, 1988);MolBlock 保留二维或三维坐标,胜在信息完整。InChI 走的是另一条路——跨库统一的标准化标识符(Heller et al., 2015);不同工具对同一分子给出不同规范 SMILES 的难题,见 O'Boyle(2012),2.2 节展开。Mol 对象与 MolBlock 的对应关系可以列成一张小抄:
- 节点属性表 ↔ 原子块:每原子一行的坐标、元素与属性列;
- 边表 ↔ 键块:每键一行的两端编号与键型代码;
- 邻接结构 ↔ 计数行:原子数与键数先行声明,读入时按数分配空间;
- 一分子一记录 ↔ "$$$$":SDF 的记录边界,也是数据集的行边界。
再看保真性。Mol 对象到 MolBlock 的往返基本无损:节点与边属性逐行落盘,再读回时按计数行重建同一张图;损失主要在坐标的小数位截断。SMILES 的往返则丢掉全部坐标信息——一维串里没有它们的位置。跨工具往返是另一回事:各家工具的芳香判据与规范化规则不同,同一分子经不同工具转手可能得到写法互异的输出,这正是标准化标识符与"通用 SMILES"工作要解决的问题(Heller et al., 2015; O'Boyle, 2012)。选哪种格式,取决于要保住什么:结构加性质用 SDF,紧凑交换用 SMILES,跨库对账用 InChI。
2.1.7 回到主线:一切特征化的地基
1.2 节说三种面貌里图最"结构";现在可以说得更准确:Mol 对象就是图表示的工程化身,节点与边属性正是特征化的原始字段。第 3 章的图卷积把原子特征向量沿邻接表传播,消息传递用的就是 2.1.2 的邻居清单;第 4 章的生成模型把"加一个原子、连一条键"定义为动作空间,动作的执行者就是可编辑态的分子;DeepChem 与 TorchDrug 的特征化管线无一不以 Mol 对象为入口。
这套表示也有边界:它不含三维构象;质子化状态与互变异构取决于输入约定,同一化合物可能对应多张不同的图;金属与配位键的表示仍是开放问题。2.6 节的清洗与标准化工序,正是为了让进入模型的每张图都站得住。下一节先解决"怎么把分子写成一行字"——SMILES。
关键术语
- 分子图 (molecular graph)
- 以原子为节点、化学键为边的图,是分子在化学信息学中的基本结构表示。
- 标注图 (labeled graph)
- 节点与边均携带属性函数的图;分子图的化学信息主要存放在属性里。
- 多重图 (multigraph)
- 允许两点间平行边的图;分子图不是多重图,键级吸收了"多重"信息。
- 邻接表 (adjacency list)
- 每节点一张邻居清单的稀疏存储,空间 Θ(V+E),分子图的机内形式。
- 邻接矩阵 (adjacency matrix)
- V×V 的稠密存储与代数工具,空间 Θ(V²),稀疏分子图上浪费严重。
- 隐式氢 (implicit hydrogen)
- 由价规则推导并折叠为原子计数的氢,不占据图的节点。
- 显式氢 (explicit hydrogen)
- 作为真实节点存在于图中的氢;力场、pKa 与三维任务通常必需。
- 化合价检查 (valence checking)
- 逐原子比较键级和与元素允许价的过程,超价即拒绝,是 sanitize 的第一道关卡。
- 结构清洗 (sanitization)
- 价态计算、环感知、凯库勒化、共轭与芳构化感知、立体化学指派的按序流水线。
- 凯库勒化 (kekulization)
- 为芳香体系指派合法交替单双键的操作,与芳构化感知互为逆操作。
- 最小环集 (SSSR)
- 描述分子环系的最小基本环集合,环感知阶段求出并缓存。
- MolBlock / SDF (molfile / structure-data file)
- Mol 对象的文本序列化格式;SDF 以 $$$$ 分隔多记录并携带数据字段。
参考文献与延伸阅读
- Landrum G, et al. 2026. RDKit: Open-Source Cheminformatics. RDKit 官方文档(Getting Started · RDKit Book),2026.03 系列.
- Weininger D. 1988. SMILES, a chemical language and information system. 1. Introduction to methodology and encoding rules. Journal of Chemical Information and Computer Sciences 28:31–36.
- Dalby A, Nourse JG, Hounshell WD, et al. 1992. Description of several chemical structure file formats used by computer programs developed at Molecular Design Limited. Journal of Chemical Information and Computer Sciences 32:244–255.
- Heller SR, McNaught A, Pletnev I, et al. 2015. InChI, the IUPAC International Chemical Identifier. Journal of Cheminformatics 7:23.
- O'Boyle NM. 2012. Towards a Universal SMILES representation — a standard method to generate canonical SMILES based on the InChI. Journal of Cheminformatics 4:22.