You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何用RDKit从mol文件获取所有含4个非氢原子的子结构?

提取所有含4个非氢原子的分子子结构:问题与解决方案

问题背景

需要从大分子中提取所有包含4个非氢原子的子结构,尝试过基于原子半径的提取方法,但存在两个问题:

  • 无法覆盖所有目标子结构(示例分子中的部分4原子子结构在半径1、2的结果中未出现)
  • 设置半径为3时代码直接报错

原测试代码

from rdkit import Chem
from rdkit.Chem import Draw
from rdkit.Chem.Draw import IPythonConsole
from rdkit.Chem import AllChem
AllChem.SetPreferCoordGen(True)

def getSubmolRadN(mol, radius):
    atoms=mol.GetAtoms()
    submols=[]
    for atom in atoms:
        env=Chem.FindAtomEnvironmentOfRadiusN(mol, radius, atom.GetIdx())
        amap={}
        submol=Chem.PathToSubmol(mol, env, atomMap=amap)
        subsmi=Chem.MolToSmiles(submol, rootedAtAtom=amap[atom.GetIdx()], canonical=False)
        submols.append(Chem.MolFromSmiles(subsmi, sanitize=False))
    return submols

mol = Chem.MolFromSmiles('C=C(S)C(N)(O)C')

# 半径1测试
submols = getSubmolRadN(mol,1)
Draw.MolsToGridImage(submols, highlightAtomLists=[[0] for _ in range(len(submols))], molsPerRow=5)

# 半径2测试
submols = getSubmolRadN(mol,2)
Draw.MolsToGridImage(submols, highlightAtomLists=[[0] for _ in range(len(submols))], molsPerRow=5)

# 半径3测试(报错)
submols = getSubmolRadN(mol,3)
Draw.MolsToGridImage(submols, highlightAtomLists=[[0] for _ in range(len(submols))], molsPerRow=5)

问题分析

原方法的核心缺陷:

  1. 覆盖不全:基于单原子半径扩展的方式,只能提取以某个原子为中心、半径范围内的子结构,无法覆盖所有4非氢原子的组合(比如线性4原子链可能不属于任何原子的半径2结构)
  2. 报错原因:当设置的半径超过分子中原子的最大可达距离时,Chem.FindAtomEnvironmentOfRadiusN会返回无效环境,导致后续子结构生成失败

解决方案:直接枚举所有4非氢原子组合

最直接的方式是生成所有非氢原子的4元组合,提取对应子结构并去重,确保不遗漏任何目标子结构:

from rdkit import Chem
from rdkit.Chem import Draw
from rdkit.Chem.Draw import IPythonConsole
from rdkit.Chem import AllChem
from itertools import combinations

AllChem.SetPreferCoordGen(True)

def get_all_4_nonh_substructures(mol):
    # 筛选所有非氢原子的索引
    nonh_atom_indices = [atom.GetIdx() for atom in mol.GetAtoms() if atom.GetAtomicNum() != 1]
    submols = []
    seen_smiles = set()
    
    # 生成所有4个非氢原子的组合
    for idx_comb in combinations(nonh_atom_indices, 4):
        # 用足够大的半径确保包含选中原子间的所有连接键
        env = Chem.FindAtomEnvironmentOfRadiusN(mol, 99, list(idx_comb))
        amap = {}
        # 提取子结构,不包含氢原子
        submol = Chem.PathToSubmol(mol, env, atomMap=amap, includeHs=False)
        # 生成规范化SMILES用于去重
        sub_smiles = Chem.MolToSmiles(submol, canonical=True)
        if sub_smiles not in seen_smiles:
            seen_smiles.add(sub_smiles)
            submols.append(submol)
    return submols

# 测试示例分子
mol = Chem.MolFromSmiles('C=C(S)C(N)(O)C')
target_submols = get_all_4_nonh_substructures(mol)

# 可视化结果
Draw.MolsToGridImage(target_submols, molsPerRow=5)

方案优势

  • 全覆盖:枚举所有4非氢原子的组合,确保没有遗漏任何符合条件的子结构
  • 去重高效:通过规范化SMILES过滤重复子结构,避免冗余结果
  • 稳定性高:不会因半径设置过大而报错,适配任意大小的分子

备选改进:修复原半径方法

如果坚持使用半径扩展的思路,需要增加有效性检查并合并去重:

def get_submol_rad_improved(mol, max_radius):
    submols = []
    seen_smiles = set()
    atoms = mol.GetAtoms()
    for atom in atoms:
        for radius in range(1, max_radius+1):
            try:
                env = Chem.FindAtomEnvironmentOfRadiusN(mol, radius, atom.GetIdx())
                amap = {}
                submol = Chem.PathToSubmol(mol, env, atomMap=amap, includeHs=False)
                # 检查子结构非氢原子数是否为4
                if len([a for a in submol.GetAtoms() if a.GetAtomicNum()!=1]) ==4:
                    sub_smiles = Chem.MolToSmiles(submol, canonical=True)
                    if sub_smiles not in seen_smiles:
                        seen_smiles.add(sub_smiles)
                        submols.append(submol)
            except:
                continue
    return submols

# 使用示例
improved_submols = get_submol_rad_improved(mol, 3)
Draw.MolsToGridImage(improved_submols, molsPerRow=5)

注意事项

这种方法仍可能遗漏部分子结构,仅适合对提取范围有特定中心原子需求的场景,优先推荐直接枚举的方案。

内容的提问来源于stack exchange,提问作者meadeytabeedy

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.24 08:24:56