3. RDKit 安装与基础操作:环境配置、分子对象创建与 SMILES 转换
好,咱们开始第三章。这一章是整个ADMET特征筛选流程的基石——RDKit。说白了,没有RDKit,后面所有分子描述符的计算都是空谈。我当年刚入行时,为了配这个环境折腾了一下午,现在回想起来,其实大部分坑都能提前避开。
3.1 环境配置:你得先有把好用的刀
RDKit的安装,我强烈建议你通过Conda来管理。为什么?因为它的依赖链太长,用pip容易碰上一堆编译错误。我个人习惯用Miniconda,轻量,够用。
创建一个干净的环境,指定Python 3.10,稳得很。
conda create -n rdkit-env python=3.10
conda activate rdkit-env
然后直接安装RDKit。注意,别从默认通道装,从conda-forge拿,版本更新而且包更全。
conda install -c conda-forge rdkit
安装完成后,验证一下。
python -c "from rdkit import Chem; print(Chem.RDKFingerprint)"
python -c "import rdkit; print(rdkit.__version__)"
能正常输出,就说明装好了。如果报错,大概率是依赖冲突。嗯,这时别硬装,重新创建个环境试试。
我曾经在Windows上直接用pip install rdkit,结果编译了40分钟,最后报了个VC++错误。后来直接用conda install -c conda-forge rdkit,三分钟搞定。别跟自己过不去。
另外,为了后续可视化分子结构,顺手装上Jupyter和ipywidgets。
conda install -c conda-forge jupyter ipywidgets
conda install -c conda-forge matplotlib
用conda list | grep rdkit可以快速检查是否安装成功及版本号。别忘了在Jupyter里激活widgets:jupyter nbextension enable --py widgetsnbextension。
3.2 分子对象创建:从字符串到化学结构
环境配好,咱们开始上手干活。RDKit中最核心的对象就是Mol对象。你想想看,它就是一个分子在计算机里的“分身”。
3.2.1 从SMILES创建
最常见的方式,就用SMILES。我平时做数据清洗时,第一行代码永远是这玩意儿。
from rdkit import Chem
# 最简单的一个分子:乙醇
mol = Chem.MolFromSmiles("CCO")
print(mol)
输出应该是
smiles_str = " CCO\n"
mol = Chem.MolFromSmiles(smiles_str.strip())
print(mol.GetNumAtoms()) # 输出3
3.2.2 从Mol文件载入
有时候数据是从供应商给的SDF或MOL文件里读出来的。RDKit也支持直接解析。
mol_from_file = Chem.MolFromMolFile("path/to/molecule.mol")
print(mol_from_file.GetNumAtoms())
也可以批量读SDF文件,这个在ADMET数据集处理里非常常见。
suppl = Chem.SDMolSupplier("path/to/compounds.sdf")
for mol in suppl:
if mol is not None:
print(mol.GetNumAtoms())
创建Mol对象后,一定要先检查是否为None。我早期写脚本时,忘了检查,结果后续算描述符时直接崩溃。所以养成好习惯:if mol is not None: ...
3.3 SMILES与分子转换:读懂化学的通用语言
有了Mol对象,我们就可以在SMILES和其他表示形式之间自由切换了。这里有个坑,SMILES可能不唯一——同样的分子,写法可以千变万化。但RDKit可以帮你规范化。
3.3.1 向SMILES转换
从Mol对象生成SMILES,用MolToSmiles。这个函数默认会做一次规范化,帮你统一格式。
from rdkit import Chem
mol = Chem.MolFromSmiles("C1=CC=CC=C1") # 苯环的SMILES
smiles_canonical = Chem.MolToSmiles(mol)
print(smiles_canonical) # 输出 c1ccccc1
看到了吧?原来的大写C变成了小写c,位置也变了。这就是规范化的标准表示。
3.3.2 获得所有SMILES与原子SMILES
有时候你需要知道所有可能的SMILES表示,使用MolToSmiles的allBondsExplict等参数可以做到。或者用MolToRandomSmiles生成随机SMILES,用来做数据增强。
import random
from rdkit import Chem
mol = Chem.MolFromSmiles("CCO")
random_smiles = Chem.MolToRandomSmiles(mol, random)
print(random_smiles) # 每次输出可能不同
更细粒度的是,你可以获取某个原子在SMILES中的对应位置——这在分析反应中心时极有用。
atom_smiles = Chem.MolFragmentToSmiles(mol, atomsToUse=[1]) # 只包含氧原子和它周围的键
print(atom_smiles) # 输出 O
3.3.3 SMARTS与InChI转换
除了SMILES,RDKit还支持SMARTS(子结构模式)和InChI(国际化学标识)。
SMARTS常用于模式匹配。比如你想查所有芳香性碳原子:
pattern = Chem.MolFromSmarts("c")
mol = Chem.MolFromSmiles("c1ccccc1")
matches = mol.GetSubstructMatches(pattern)
print(len(matches)) # 输出6
InChI转换则更侧重唯一性标识:
inchi = Chem.MolToInchi(mol)
print(inchi) # InChI=1S/C6H6/c1-2-4-6-5-3-1/h1-6H
mol_from_inchi = Chem.MolFromInchi(inchi)
print(Chem.MolToSmiles(mol_from_inchi)) # c1ccccc1
这下明白了吧?SMILES、SMARTS、InChI这三兄弟,各有各的用处。我个人习惯是:日常处理用SMILES,模式匹配用SMARTS,需要全球唯一标识时用InChI。
我在做ADMET数据清洗时,经常用InChI来去重。两个SMILES看起来一样,但写法不同,用字符串比较就失效了。转成InChI后再比较,保证唯一性。
3.4 本章知识结构图
我把这一章的核心逻辑画成了一张图,方便你从高处理解。
3.5 基础操作与常用技巧
再往后看,Mol对象创建好了,怎么用它做点事情?这里列几个我每天都会用到的操作。
3.5.1 原子与键的遍历
mol = Chem.MolFromSmiles("CCO")
for atom in mol.GetAtoms():
print(atom.GetAtomicNum(), atom.GetSymbol(), atom.GetDegree())
for bond in mol.GetBonds():
print(bond.GetBondType(), bond.GetBeginAtomIdx(), bond.GetEndAtomIdx())
3.5.2 添加氢原子与计算分子式
mol = Chem.MolFromSmiles("CCO")
mol_h = Chem.AddHs(mol) # 显示所有氢
print(mol_h.GetNumAtoms()) # 9(原来的3个原子+6个H)
formula = Chem.rdMolDescriptors.CalcMolFormula(mol)
print(formula) # C2H6O
3.5.3 分子可视化(在Jupyter中)
from rdkit.Chem import Draw
mol = Chem.MolFromSmiles("CCO")
img = Draw.MolToImage(mol, size=(300, 300))
display(img) # Jupyter中显示
RDKit的API非常统一:用MolFrom*创建,用MolTo*转换。记住这个原则,后面学描述符计算时顺风顺水。
好了,这一章的内容就到这。环境配好了,分子能创建能转换了,下一步我们就可以开始真正计算ADMET描述符了。这条路,咱们一步步趟。