如何将化学分子SMILES字符串转化为Pytorch图数据结构——ESOL分子水溶性数据集解析

news2025/1/21 8:52:42

硬核原创,转载请注明出处:
https://leytton.blog.csdn.net/article/details/130406553

一、前言

在用Pytorch图神经网络对化学分子进行数据分析的时候,经常使用现有的数据集。看到自动处理完毕的数据结构,里面的特征值让我们一脸懵逼,不知道代表的是什么含义。本文将带大家分析这些数据结构的来龙去脉。

二、数据原始特征

在使用图神经网络(GNN)对化学分子进行水溶性预测的实验中,加载了MoleculeNetESOL数据集。我们打开原始的csv文件,结构是这样的(非专业翻译,有误恳请留言纠正):

表头含义示例
Compound ID化合物ID2-pyrrolidone
ESOL predicted log solubility in mols per litreESOL预测对数溶解度(mol/L)0.243
Minimum Degree最小度1
Molecular Weight分子量85.10600000000001
Number of H-Bond Donors氢键供体数1
Number of Rings环数1
Number of Rotatable Bonds可旋转键数0
Polar Surface Area极性表面积29.1
measured log solubility in mols per litre测量对数溶解度(mol/L)1.07
smiles分子SMILES字符串O=C1CCCN1

从smiles中可以看到,这个分子有OCN、H(一般省略)四种元素,除去H有六个原子。

三、分析预处理数据

加载数据

如下面代码,加载ESOL数据集后将其打印出来:

from torch_geometric.datasets import MoleculeNet

data = MoleculeNet(root="data", name="ESOL")

print("Dataset Size:", len(data))
print("Dataset classes:", data.num_classes)
print("Dataset features:", data.num_features)
Dataset Size: 1128
Dataset classes: 734
Dataset features: 9

从结果可以看到,有1128个分子样本,734种类型,每个分子有9个特征。

分析数据

我们选择第11个分子(smiles比较短)进行分析:

print("Sample:", data[10])
print("Sample y:", data[10].y)
Sample: Data(x=[6, 9], edge_index=[2, 12], edge_attr=[12, 3], smiles='O=C1CCCN1', y=[1, 1])
Sample y: tensor([[1.0700]])

可以看到x、edge_index、edge_attr 是二维数组,y可以看成一个值(水溶性)。

关于水溶性参考《理化性质|(logSw和logP)小分子化合物水溶性和脂溶性指标》

画出分子图

根据SMILES字符串,将其分子图画出来:

from rdkit import Chem
from rdkit.Chem import Draw

molecule = Chem.MolFromSmiles(data[10]["smiles"])
# Draw.MolToFile(molecule, "mol.png")
Draw.MolToImage(molecule)

在这里插入图片描述

edge_index数据分析

edge_index数组打印出来:

print(data[10].edge_index.T)
tensor([[0, 1],
        [1, 0],
        [1, 2],
        [1, 5],
        [2, 1],
        [2, 3],
        [3, 2],
        [3, 4],
        [4, 3],
        [4, 5],
        [5, 1],
        [5, 4]])

这是O、C、N六个原子的连接关系。

x数据分析

x数组打印出来:

print(data[10].x.shape)
print(data[10].x)
torch.Size([6, 9])
tensor([[8, 0, 1, 5, 0, 0, 3, 0, 0],
        [6, 0, 3, 5, 0, 0, 3, 0, 1],
        [6, 0, 4, 5, 2, 0, 4, 0, 1],
        [6, 0, 4, 5, 2, 0, 4, 0, 1],
        [6, 0, 4, 5, 2, 0, 4, 0, 1],
        [7, 0, 3, 5, 1, 0, 3, 0, 1]])

这就不太看得懂了,看起来像是描述6个原子9个特征的二维数组。

四、真相:从SMILES字符串得到

作者查阅资料无果,那么久只能去分析MoleculeNet中的代码了,到底对原始数据进行了怎样的处理,x中的数据是怎样来的。

点进去看到一个process函数应该是处理数据的,我对其进行了注释:

# Format: name: [display_name, url_name, csv_name, smiles_idx, y_idx]
    names = {
        'esol': ['ESOL', 'delaney-processed.csv', 'delaney-processed', -1, -2],
        'freesolv': ['FreeSolv', 'SAMPL.csv', 'SAMPL', 1, 2],
        'lipo': ['Lipophilicity', 'Lipophilicity.csv', 'Lipophilicity', 2, 1],
        'pcba': ['PCBA', 'pcba.csv.gz', 'pcba', -1,
                 slice(0, 128)],
        'muv': ['MUV', 'muv.csv.gz', 'muv', -1,
                slice(0, 17)],
        'hiv': ['HIV', 'HIV.csv', 'HIV', 0, -1],
        'bace': ['BACE', 'bace.csv', 'bace', 0, 2],
        'bbbp': ['BBPB', 'BBBP.csv', 'BBBP', -1, -2],
        'tox21': ['Tox21', 'tox21.csv.gz', 'tox21', -1,
                  slice(0, 12)],
        'toxcast':
        ['ToxCast', 'toxcast_data.csv.gz', 'toxcast_data', 0,
         slice(1, 618)],
        'sider': ['SIDER', 'sider.csv.gz', 'sider', 0,
                  slice(1, 28)],
        'clintox': ['ClinTox', 'clintox.csv.gz', 'clintox', 0,
                    slice(1, 3)],
    }
    
def process(self):
        with open(self.raw_paths[0], 'r') as f: #读取原始数据文件
            dataset = f.read().split('\n')[1:-1] #按行分割,并去掉第一行
            dataset = [x for x in dataset if len(x) > 0]  # 去掉空行

        data_list = []
        for line in dataset:  #遍历每行
            line = re.sub(r'\".*\"', '', line)  # 去掉".*"字符串
            line = line.split(',') #逗号分隔

            smiles = line[self.names[self.name][3]] #获取到smiles字符串
            ys = line[self.names[self.name][4]] #获取到y值
            ys = ys if isinstance(ys, list) else [ys] #将y值统一成数组形式

            ys = [float(y) if len(y) > 0 else float('NaN') for y in ys] #将y转成float类型
            y = torch.tensor(ys, dtype=torch.float).view(1, -1) #将y转成torch.float类型
			
			# 重点:获取x、edge_index、edge_attr数据,需要查看from_smiles函数
            data = from_smiles(smiles)  
            data.y = y  #y处理完毕

            if self.pre_filter is not None and not self.pre_filter(data):
                continue

            if self.pre_transform is not None:
                data = self.pre_transform(data)

            data_list.append(data)

        torch.save(self.collate(data_list), self.processed_paths[0])

从上面分析可以知道,原来x、edge_index、edge_attr数据都是通过将smile字符串传递到from_smiles函数获取到的!

from_smiles函数如下:

def from_smiles(smiles: str, with_hydrogen: bool = False,
                kekulize: bool = False) -> 'torch_geometric.data.Data':
    # 太多了省略。。。
    return Data(x=x, edge_index=edge_index, edge_attr=edge_attr, smiles=smiles)

这下可以参考这个函数的代码进一步分析了。

我们直接指定smiles进行分析:

smiles='O=C1CCCN1'
from rdkit import Chem

mol = Chem.MolFromSmiles(smiles)
for atom in mol.GetAtoms():
    print(f'原子序号:{atom.GetAtomicNum()}, 手性信息:{atom.GetChiralTag()}, 度:{atom.GetTotalDegree()}, 电荷:{atom.GetFormalCharge()}, 连接氢原子数:{atom.GetTotalNumHs()}, 自由基:{atom.GetNumRadicalElectrons()}, 杂化类型:{atom.GetHybridization()}, 芳香性:{atom.GetIsAromatic()}, 是否在环上:{atom.IsInRing()}')
原子序号:8, 手性信息:CHI_UNSPECIFIED, 度:1, 电荷:0, 连接氢原子数:0, 自由基:0, 杂化类型:SP2, 芳香性:False, 是否在环上:False
原子序号:6, 手性信息:CHI_UNSPECIFIED, 度:3, 电荷:0, 连接氢原子数:0, 自由基:0, 杂化类型:SP2, 芳香性:False, 是否在环上:True
原子序号:6, 手性信息:CHI_UNSPECIFIED, 度:4, 电荷:0, 连接氢原子数:2, 自由基:0, 杂化类型:SP3, 芳香性:False, 是否在环上:True
原子序号:6, 手性信息:CHI_UNSPECIFIED, 度:4, 电荷:0, 连接氢原子数:2, 自由基:0, 杂化类型:SP3, 芳香性:False, 是否在环上:True
原子序号:6, 手性信息:CHI_UNSPECIFIED, 度:4, 电荷:0, 连接氢原子数:2, 自由基:0, 杂化类型:SP3, 芳香性:False, 是否在环上:True
原子序号:7, 手性信息:CHI_UNSPECIFIED, 度:3, 电荷:0, 连接氢原子数:1, 自由基:0, 杂化类型:SP2, 芳香性:False, 是否在环上:True

如上所示,这9个特征就是x变量中每个原子的含义,对其进行一些编码变换就构造成了x变量。具体的原子更多的属性,可以参考 RDKit 文档

接下来我们分析edge_attredge_index变量含义:

for bond in mol.GetBonds(): #便利所有的键
    i = bond.GetBeginAtomIdx()
    j = bond.GetEndAtomIdx()
    print(f'连接:{i,j},{j,i}')
    print(f'键的类型:{bond.GetBondType()}, Stereo:{bond.GetStereo()}, 是否共轭:{bond.GetIsConjugated()}')
连接:(0, 1),(1, 0)
键的类型:DOUBLE, Stereo:STEREONONE, 是否共轭:True
连接:(1, 2),(2, 1)
键的类型:SINGLE, Stereo:STEREONONE, 是否共轭:False
连接:(2, 3),(3, 2)
键的类型:SINGLE, Stereo:STEREONONE, 是否共轭:False
连接:(3, 4),(4, 3)
键的类型:SINGLE, Stereo:STEREONONE, 是否共轭:False
连接:(4, 5),(5, 4)
键的类型:SINGLE, Stereo:STEREONONE, 是否共轭:False
连接:(5, 1),(1, 5)
键的类型:SINGLE, Stereo:STEREONONE, 是否共轭:True

这就是分子SMILES字符串转化成图数据结构的过程,可以看到只用到了原始数据里的SMILES字符串水溶性结果

在Pytorch官网找了半天没找到数据集的说明资料,等我分析完后,才发现,这里已经有大佬发表了相关文章。不过,如果不知道图结构数据是从SMILES字符串分析得到,很难通过关键字找到这些资料。
How to turn a SMILES string into a molecular graph for Pytorch Geometric

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/469009.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

springsecurity工作流程

Spring Security 的工作流程如下: 1.当用户请求一个受保护的资源时,Spring Security 的过滤器链会拦截该请求。 2.然后 Spring Security 会判断该请求是否认证(authenticated)和授权(authorized)。 认证(Authentication):验证用户身份,判断用户是否能登录系统。Spring Securi…

Linux应用编程(线程同步)(互斥锁)

对于一个单线程进程来说,它不需要处理线程同步的问题,所以线程同步是在多线程环境下可能需要注意的一个问题。线程的主要优势在于,资源的共享性,譬如通过全局变量来实现信息共享,不过这种便捷的共享是有代价的&#xf…

docker网桥冲突解决方法

Docker网桥网段冲突导致访问不到容器问题 三种情况 一、docker0所用网段与局域网所用网段相同,导致网桥冲突,这会造成冲突网段无法访问docker服务。 解决办法: 1.停止docker,删除冲突网桥 systemctl stop docker ip link del doc…

干货 | 中科院心理所考研复试经验分享

Hello,大家好! 这里是壹脑云科研圈,我是喵君姐姐~ 此时此刻,23年考研的小伙伴估计正在为复试进行准备吧,大家都准备得怎么样了呢? 今天为大家带来的就是我国顶级心理学研究结构—中科院心理所…

leetcode19_删除链表的倒数第 N 个结点

文章目录 题目详情分析Java代码实现 题目详情 leetcode19 给你一个链表,删除链表的倒数第 n 个结点,并且返回链表的头结点。 分析 暴力的方法,两趟遍历,第一个遍历记录总的节点数目,第二次遍历到总结点数-N个位置&…

PyTorch——利用Accelerate轻松控制多个CPU/GPU/TPU加速计算

PyTorch——利用Accelerate轻松控制多个CPU/GPU/TPU加速计算 前言官方示例控制多个CPU/GPU/TPU简单说一下设备环境导包加载数据 FashionMNIST创建一个简单的CNN模型训练函数-只包含训练训练函数-包含训练和验证训练 参考链接 前言 CPU?GPU?TPU&#xff…

边学边记——数据结构☞关于对象的比较(包括对equals()方法的重写,Comparable接口,Comparator接口的介绍)

目录 一、基本类型 二、引用类型——对象的比较 1. 关于同一性的比较 2. 关于相等性的比较 三、Comparable接口 1. 介绍 2. 实现 3. 什么叫做正确的compareTo方法的重写 四、实现Comparator接口(基于比较器比较) 1. 介绍 2. 实现 3. 使用场景…

CentOS防火墙的常用快捷命令

CentOS是免费开源的Linux发行版之一,它兼容RHEL并由社区进行维护,大多数美国服务器提供对该系统支持。在使用CentOS系统时,您需要了解一些常用命令,比如开启、查看、关闭防火墙等。本文将介绍下CentOS防火墙的常用命令。 CentOS是一种面向企业级服务器环境的Linux发行版,…

D触发器仿真实验

关于D触发器的内容见专栏的单片机原理及应用,主要是时钟脉冲出现时候,会改变输出状态。 下面来做一个D触发器的仿真实验。 部件 使用74LS74:带清除和预置端功能的双上升沿D型触发器 74LS74是一款现代集成电路芯片,属于TTL&…

火爆全网,测试用例技巧-Python实现XMind测试用例转Excel测试用例

目录:导读 前言一、Python编程入门到精通二、接口自动化项目实战三、Web自动化项目实战四、App自动化项目实战五、一线大厂简历六、测试开发DevOps体系七、常用自动化测试工具八、JMeter性能测试九、总结(尾部小惊喜) 前言 自动化测试&#x…

Jenkins中Changelog插件使用

Jenkins中Changelog插件使用 通过changlog插件获取每次提交的变更信息 一、安装changelog插件 二、使用changelog 1、新建项目,在构建环境中勾选Add Changelog Information to Environment ,输入对应的格式 %3$s(datetime-at%4$s via%1$s) %2$s(type%…

聚焦智慧燃气,美格智能亮相第25届中国国际燃气、供热技术与设备展览会

4月25~27日,第25届中国国际燃气、供热技术与设备展览会在深圳会展中心(福田)盛大举办。本次展会由中国城市燃气协会主办,自1994年举办以来已历经24届,是国内燃气行业规模巨大的综合性专业展会。美格智能携4G/5G模组、N…

Typora中的数学公式(MarkDown)

Typora中的数学公式(MarkDown) 添加数学公式方式: 1.选择:段落>公式 2.快捷键:Ctrl Shift M 3.直接输入两个美元符号并回车 展示: 空格:一个斜线\ : a \ b a b a \ b a b 换行&#x…

【河南省第二届技能大赛-物联网技术】C模块Python开发讲解

文章目录 前言题目如下什么是云平台APIAPI调用的基本流程Python实例介绍依赖库介绍API调用的基本参数请求返回值requests库PyQt5库总结源码链接 前言 这是基于样题进行讲解的文章,因为正式赛题尚未公布和样题类型相似。文章结尾提供了源码和环境链接,读…

四面阿里,成功入职阿里测试开发,分享我的真实面试题

闲话少叙 直接上干货 鉴于篇幅所限,这里不放答案,有需要的朋友可以评论区自取 1. 请自我介绍一下(需简单清楚的表述自已的基本情况,在这过程中要展现出自信,对工作有激情,上进,好学) 2. 平时工作中是怎么去…

【面试题】你都必须得掌握的vue知识

大厂面试题分享 面试题库 前后端面试题库 (面试必备) 推荐:★★★★★ 地址:前端面试题库 web前端面试题库 VS java后端面试题库大全 前言 大家好,我是前端贰货道士。最近抽空整理了下我对vue2.x的理解和认知&#…

设计师常用的素材网站有哪个推荐

即时设计资源社区聚集了许多优秀的创作者,分享了大量的优质资源。 目前,社区资源数量已达到10000,包含图标、插画、原型、设计作品等多个素材类别。这些优秀的设计作品降低了设计师思维的成本,成为设计师的宝藏材料网站。 即时设…

ML@sklearn@ML流程Part2@数据划分@KFold折叠交叉验证

文章目录 MLsklearnML流程Part2数据划分KFold折叠交叉验证Model evaluation数据划分sklearn中的模型评估demo K-fold cross-validation🎈K-foldegegeg:KFoldK-fold cross-validation ShuffleSpliteg 小结 Stratified Shuffle Splitegeg demo MLsklearnML流程Part2数…

代码随想录算法训练营第四十四天|完全背包理论基础 、518. 零钱兑换 II 、377. 组合总和 Ⅳ

文章目录 完全背包理论基础518. 零钱兑换 II377. 组合总和 Ⅳ 完全背包理论基础 纯背包问题的特点:每个物品可以无限次拿 与0-1背包唯一不同: 完全背包的物品是可以添加多次的,所以要从小到大去遍历 0-1背包不可以添加多次,需要从…

【C++】类和对象(上篇)

类和对象 面向过程和面向对象初步认识类的引入类的定义命名规范类的访问限定符及封装访问限定符封装 类的作用域类的实例化类的对象大小的计算类成员函数的this指针this指针的引出this指针的特性 面向过程和面向对象初步认识 C语言是面向过程的,关注的是过程&#…