分子表示基础:SMILES字符串、分子图、分子指纹与向量化方法

做分子生成,第一个绕不开的问题就是:怎么让深度学习模型"看懂"分子?

你不能直接把一个分子结构图扔给神经网络。模型只吃数字,不吃结构式。所以,我们需要把分子转成计算机能处理的形式。这就是分子表示。

我个人习惯把分子表示分成四个流派:字符串派(SMILES)、图流派(分子图)、指纹派(分子指纹)和向量派(向量化方法)。每个流派都有自己的脾气,咱们一个一个聊。

核心观点: 没有最好的分子表示,只有最合适的。你的下游任务决定了该选哪种表示。
分子表示方法框架图 分子结构 SMILES 字符串 CCO, c1ccccc1 分子图 节点=原子,边=键 分子指纹 MACCS, ECFP 向量化方法 One-hot, Embedding 应用场景 序列模型 → SMILES | 图神经网络 → 分子图 | 相似度搜索 → 分子指纹 | 分类/回归 → 向量化 选择建议 生成任务优先 SMILES 或分子图 | 分类/回归优先分子指纹或向量化

1. SMILES字符串——分子的"一行诗"

SMILES全称是Simplified Molecular Input Line Entry System。说白了,就是把分子结构写成一行字符串。我刚开始接触时觉得挺神奇——一个苯环居然能用 c1ccccc1 六个字符搞定。

SMILES的规则其实不复杂:

  • 原子用元素符号表示:C(碳)、O(氧)、N(氮)、c(芳香碳)等。
  • 单键直接连,双键用 =,三键用 #。
  • 分支用括号 (),比如乙醇 CCO 没分支,但异丙醇就是 CC(C)O。
  • 环用数字标记,比如苯环 c1ccccc1,数字 1 首尾配对。

举个例子,阿司匹林的SMILES长这样:

CC(=O)Oc1ccccc1C(=O)O

你看,括号、等号、数字全用上了。这串字符虽然看着乱,但模型非常爱吃。

我的经验: 我建议在做分子生成时,优先使用 Canonical SMILES(标准SMILES)。同一分子可能有多种写法,标准SMILES能保证唯一性。RDKit的 Chem.MolToSmiles() 默认就是标准输出。
注意: SMILES虽然简洁,但它丢失了三维构象信息。手性中心需要额外用 @ 或 @@ 标记,初学者容易漏掉。我曾经在一次生成任务中,因为没处理手性标记,生成的分子有一半是镜像异构体……

2. 分子图——从拓扑角度看分子

分子本质上是图结构。原子是节点,化学键是边。这个视角非常自然,也很适合图神经网络(GNN)。

用RDKit构建分子图非常方便:

from rdkit import Chem
from rdkit.Chem import rdmolops

mol = Chem.MolFromSmiles("CCO")
adj_matrix = rdmolops.GetAdjacencyMatrix(mol)
print(adj_matrix)
# [[0 1 0]
#  [1 0 1]
#  [0 1 0]]

你看,乙醇的邻接矩阵就是3x3,碳碳单键相连,碳氧单键相连。

分子图的核心信息包括:

  • 节点特征:原子类型(C、O、N...)、杂化方式、电荷、手性等。
  • 边特征:键类型(单键、双键、三键、芳香键)、键长、是否在环中等。

我在做分子性质预测项目时,用过GIN(Graph Isomorphism Network)处理分子图。效果确实好,但图的大小不一致是个麻烦——乙醇只有3个原子,阿司匹林有21个,你得做padding或者batch处理。

3. 分子指纹——结构的二进制编码

分子指纹,说白了就是一个固定长度的二进制向量。每一位代表一个子结构是否存在。最早的是MACCS指纹,166位,每个位对应一个预定义的子结构模式。

但MACCS太"死"了。现在更常用的是ECFP(Extended Connectivity Fingerprint),也叫摩根指纹。它不预定义子结构,而是从每个原子出发,逐层扩展邻居,生成哈希特征。

ECFP的生成过程我简单说一下:

  1. 对每个原子,根据其类型、度数、电荷等计算一个初始标识符。
  2. 逐层融合邻居的标识符,生成新的特征。
  3. 把最终的特征哈希到固定长度的位向量里。

用RDKit算ECFP只需几行代码:

from rdkit import Chem
from rdkit.Chem import AllChem

mol = Chem.MolFromSmiles("CCO")
ecfp = AllChem.GetMorganFingerprintAsBitVect(mol, radius=2, nBits=2048)
print(ecfp.ToBitString()[:50])
# 00100101001001100100101001001001001001001001100100

2048位的向量,每一位是0或1。这就是分子指纹。

避坑指南: 我曾经在分子相似度搜索任务中,直接用完整2048位ECFP做PCA降维,结果信息损失很大。后来改用 t-SNE 或 UMAP,保留拓扑结构的同时还能可视化。要降维,优先考虑保留局部结构的方法。

4. 向量化方法——让分子走进深度学习

SMILES是字符串,分子图是图结构,分子指纹是二进制向量。深度学习模型要的是连续值向量。怎么转?

常见做法有以下几种:

  • One-hot编码:对SMILES字符集做one-hot。简单但维度爆炸,且丢失了字符之间的关联。
  • Embedding层:把SMILES字符映射到低维稠密向量。这是主流做法,能学到字符的语义关系。
  • 分子指纹直接作为向量:ECFP的2048位向量本身就是特征,但稀疏且离散,很多模型吃不下。
  • 图读出(Graph Readout):用GNN提取分子图的全局特征向量,比如对节点特征做 sum/mean/max pooling。

我个人的建议是:

  • 如果用序列模型(RNN/Transformer),走SMILES + Embedding路线。
  • 如果用图神经网络,直接用分子图 + Readout。
  • 如果用传统ML模型(随机森林、SVM),用分子指纹。

对占比分子生成来说,SMILES + Embedding 和 分子图 + GNN 是两条主流路线。我本人更倾向后者——图结构保留了完整的拓扑信息,不容易被SMILES的语法陷阱误导。

5. 四种表示方法的对比与选择

我把它们整理成一张表,方便你对比:

表示方法 数据形式 维度 是否保留拓扑 适合模型 缺点
SMILES 字符串 可变长度 间接保留 RNN, Transformer 语法敏感,有无效序列风险
分子图 图结构 可变(节点+边) 直接保留 GNN, GCN, GAT 图大小不一,需要padding
分子指纹 二进制向量 固定(如2048) 部分保留 随机森林, SVM 信息有损,不可逆
向量化方法 稠密向量 固定(如128/256) 取决于来源 全连接, 各类深度学习 需要额外训练Embedding

你想想看,选哪种表示,其实取决于你的模型和任务。我做分子生成,大部分时间都在跟SMILES和分子图打交道。指纹嘛,更多用在虚拟筛选和相似度搜索上。

一句话总结: SMILES给序列模型吃,分子图给图神经网络吃,分子指纹给传统ML吃,向量化方法给各种深度学习模型吃。没有银弹,只有权衡。