进一步认识Deepchem的分子特征化: 将化学分子结构作为到随机森林\CNN\RNN\GNN等机器学习模型输入的三种方法


'''

by wufeil

进一步认识分子特征化:将化学分子结构作为到随机森林\CNN\RNN\GNN等机器学习模型的输入

    如何将一个分子SMile表示的分子输入到机器学习/深度学习中呢?例如:CH3CH3CH3

    这里将进行介绍。

    使用机器学习处理分子数据最重要的一步就是将分子转换成机器学习算法可以处理的数据格式。

    deepchem特征化分子的方法为Featurizer类。有三种方式的特征化分子:
        (1) 直接使用molnet内置数据集的时候,只需要转递特征化的名字即可,例如:featurizer='ECFP'或者featurizer='GraphConv'
        (2) 直接创立一个特征器featurer,应用与分子,如下代码:

'''

import rdkit
from rdkit import Chem
import deepchem as dc

'''
查看deepchem和rdkit的版本
'''
print('Rdkit version:', rdkit.__version__)
print('Deepchem version', dc.__version__)

'''
使用RDKIT使用分子的SMILES构建分子,详见:https://www.rdkit.org/docs/source/rdkit.Chem.rdmolfiles.html
返回一个mol对象。
'''
testsmi = 'CC(C1=C(C=CC(=C1Cl)F)Cl)OC2=C(N=CC(=C2)C3=CN(N=C3)C4CCNCC4)N'
mol = Chem.MolFromSmiles(testsmi)
print(mol)


'''
这里必须要说明的是:
  deepchem中的dc.feat.CircularFingerprint()特征化方法,按照文档的说法,可以输入SMILES,直接特征化。
  但是在实际使用中发生报错:
    Boost.Python.ArgumentError: Python argument types in
    rdkit.Chem.rdMolDescriptors.GetMorganFingerprintAsBitVect(str, int) did not match C++ signature
  
  不管是百度或者Google,都没有明确的说法,大部分是认为是与C++有关的boost模块发生了兼容问题,但是都没有有效的解决方法。
  
  经过我测试发现,其实这是因为输入类型错误导致的。虽然在deepchem的文档例子中,dc.feat.CircularFingerprint()是可以输入Simles,
  但是实际不行,如果先使用RDKit将SMILE转换为Mol对象以后则不会出现该问题。
  
  其他的类型错误也是会报上述错误。
  
  当然这也可能是因为我RDKIT与deepchem的版本不匹配的问题。
'''
smiles = [
  'O=Cc1ccc(O)c(OC)c1',
  'CN1CCC[C@H]1c2cccnc2',
  'C1CCCCC1',
  'c1ccccc1',
  'CC(=O)O',
]
SIMLES =[]
for smile in smiles:
    SIMLES.append(Chem.MolFromSmiles(smile))
'''
CircularFingerprint特征化

  在加载数据时,可以使用这个对象,将分子统一进行特征化处理。
  当然,SIMLES也要生成不同的构象,可以使用deepchem.utils.conformers进行处理
'''
featurizer = dc.feat.CircularFingerprint(size=1024)
ecfp = featurizer.featurize(SIMLES)
print(ecfp)
print(len(ecfp))


'''
RDKitDescriptors特征化

  RDKitDescriptors特征化的方法是使用RDKIT包,计算分子chemical discrptors的值。
  这些是基本的物理和化学特性:分子量,极性表面积,氢键供体和受体的数量等。
  这对于预测依赖于这些高级特性而不是详细分子结构的事物最有用。
'''
rdkit_featurizer = dc.feat.RDKitDescriptors()
mol = Chem.MolFromSmiles('CCC') #先将Smiles转换为Mol对象
features = rdkit_featurizer([mol])[0] #[0]是因为返回是各分子的列表

print('The number of descriptors present is: ', len(features), '\n')
'''
111个描述器(descriptors)
因此features = rdkit_featurizer([mol])返回的shape是(n,111), n为分子数
'''
for feature, descriptor in zip(features, rdkit_featurizer.descriptors):
  '''
  逐一打印描述器及其特征值
  '''
  print(feature, ' ' ,descriptor)


'''
WeaveFeaturizer and MolGraphConvFeaturizer特征化

  WeaveFeaturizer and MolGraphConvFeaturizer特征化主要是适用于图神经网络。
  正如我们之前的关于内置数据集的内容,将图神经网络应用于分子的时候,使用ConvMolFeaturizer方法将分子转换成ConvMol/WeaveMol对象。
  在这个对象里面,我们可以提取出邻接矩阵、节点矩阵等图神经网络需要的输入
  将分子用一张图来代表。
  
  DeepChem支持许多不同的基于图形的模型。 其中一些要求分子以稍微不同的方式进行特征化。 
  因此,另外还有两个适用于图神经网络的分子转换器,称为WeaveFeaturizer和MolGraphConvFeaturizer。
  他们返回的是ConvMol对象。更具体一点,WeaveFeaturizer返回的是WeaveMol对象,MolGraphConvFeaturizer返回的是ConvMol对象
  
  它们各自将分子转换为特定模型使用的不同类型的Python对象。 
  使用任何基于图形的模型时,只需查看文档以查看需要与之配合使用的特征化器。
  
  当然,如果是不使用deepchem里面的图神经网络模型,那么只需要利用WeaveFeaturizer和MolGraphConvFeaturizer转换器生成ConvMol对象,
  然后从ConvMol对象中提取出连接矩阵等信息。
  
  具体用法请参考:https://deepchem.readthedocs.io/en/latest/api_reference/dataclasses.html?highlight=WeaveMol#deepchem.feat.mol_graphs.WeaveMol
'''
featurizer = dc.feat.ConvMolFeaturizer()
X = featurizer.featurize([mol])
print(type(X[0]))
print(X)
print(X[0].get_atom_features())
print(X[0].get_atoms_with_deg(2))
print(X[0].get_num_atoms_with_deg(2))
print(X[0].get_adjacency_list())


featurizer = dc.feat.WeaveFeaturizer()
X = featurizer.featurize([mol])
print(type(X[0]))
print(X[0])
print(X[0].get_atom_features())
'''
注意:
  WeaveMol对象没有get_atoms_with_deg/get_num_atoms_with_deg/get_adjacency_list等属性。
'''


'''
CoulombMatrix
库伦矩阵

到目前为止,我们研究的所有模型都只考虑了分子的固有特性:组成该分子的原子列表和连接它们的键。 
当使用柔性分子时,您可能还需要考虑分子可以呈现的不同构象。 例如,当药物分子与蛋白质结合时,
结合强度取决于原子对之间的特定相互作用。 为了预测结合强度,您可能需要考虑各种可能的构象,并使用在进行预测时将它们考虑在内的模型。

库仑矩阵是分子构象的一种流行特征。

两个电荷之间的静电库仑相互作用与q_1 q_2 / r 成正比,其中 q_1 和 q_2 是电荷, r 是它们之间的距离。 
对于具有N个原子的分子,库仑矩阵是N×N的矩阵,其中每个元素给出两个原子之间静电相互作用的强度。 它包含有关原子上的电荷以及原子之间的距离的信息。

要应用这种特征化方法,我们首先需要分子的一系列构象。 
我们可以使用ConformerGenerator类来执行此操作。 
它需要一个RDKit分子,生成一组能量最小的构象异构体,然后将其修剪为仅包括彼此显着不同的构象异构体。 
让我们尝试将其用于丙烷。
'''
from rdkit import Chem
from deepchem.utils import conformers
generator = conformers.ConformerGenerator(max_conformers=5)
butane_mol = generator.generate_conformers(Chem.MolFromSmiles('CCCC'))

'''
butane_mol.GetConformers()生成构象的rdkit.Chem.rdchem.Conformer对象
'''
print(butane_mol.GetConformers())
conformers_mols = butane_mol.GetConformers()
print(type(conformers_mols[0]))


'''
dc.feat.CoulombMatrix生成库伦矩阵

  关于shape:
    features里面有很多0,这是因为使用20个原子来做库伦矩阵,如果不足20个原子则会用0补足
    这里最后的矩阵形状为:
      (1, 3, 20, 20) 1是[],3是’CCCC‘的3个构象,20*20是库伦矩阵
'''
coulomb_mat = dc.feat.CoulombMatrix(max_atoms=20)
features = coulomb_mat([butane_mol])
print(features)
print(features.shape)

for i, j in zip(features[0,1,:,:].flat, features[0,2,:,:].flat):
  if i != j :
    print('XXX')
'''
有输出,说明两个构象的库伦矩阵真的不一致。
'''



'''
CoulombMatrixEig
库伦特征值矩阵


库仑矩阵的一个重要特征是它们对于分子的旋转和平移是无关的,因为原子间的距离和原子序数不变。
这使学习变得容易。 因为,旋转分子不会改变其物理性质。 
如果特征确实发生了变化,则模型将被迫学习旋转并不重要,但是如果特征不变,则模型将自动获得此属性。

库仑矩阵在另一个重要的对称性上是不变的:原子指数的排列。 分子的物理性质并不取决于我们称哪个原子为“原子1”,而库仑矩阵则取决于。
 为了解决这个问题,我们引入了CoulumbMatrixEig功能化器,该功能器使用了Coulumb矩阵的特征值谱,并且对于原子索引的随机排列是不变的。 
 这种特征化的缺点是它包含的信息要少得多(N 个特征值而不是N 乘以N 的矩阵),因此模型在学习方面将受到更多的限制。
 
 oulombMatrixEig继承自CoulombMatrix,并通过首先计算分子的不同构象异构体的库仑矩阵,然后计算每个库仑矩阵的特征值来使分子特征化。 
 然后填充这些特征值到20(设定的原子数)。
'''
coulomb_mat_eig = dc.feat.CoulombMatrixEig(max_atoms=20)
features = coulomb_mat_eig([butane_mol])
print(features)


''''
总结:

  有三种方法将分子特征化,使之适合机器学习/深度学习模型:
    
    (1)对于内置的数据集,可以直接使用featurizer = dc.feat.CircularFingerprint()等一些系列特征化方法,将SMILES的list转化为特征,
    这种方法适合与RNN\CNN\Randomforest等方法;输入是:Mol对象list,输出是numpy矩阵
    
    (2)RDKitDescriptors:
        rdkit_featurizer = dc.feat.RDKitDescriptors()
        基于性质的特征,例如分子质量等;这种方法适合与RNN\CNN\Randomforest等方法;输入是Mol对象list,输出是numpy矩阵
        
    (3) 适合图神经网络的WeaveFeaturizer and MolGraphConvFeaturizer:
        featurizer = dc.feat.WeaveFeaturizer()
        featurizer = dc.feat.ConvMolFeaturizer()    
        基于原子结构的特征:输入是Mol对象list,输出是:ConvMol/WeaveMol对象。
        
    (4) 与构象有关的库伦矩阵
        输入的是:rdkit.Chem.rdchem.Conformer对象,由generator = conformers.ConformerGenerator(max_conformers=5);
        butane_mol = generator.generate_conformers(Chem.MolFromSmiles('CCCC'))生成。
        输出是:numpy矩阵
        coulomb_mat = dc.feat.CoulombMatrix(max_atoms=20)
        features = coulomb_mat([butane_mol])
        
        当然也可以库伦矩阵的特征值:
        coulomb_mat_eig = dc.feat.CoulombMatrixEig(max_atoms=20)
        features = coulomb_mat_eig([butane_mol])
        
现在还存在一个关键问题:

    图神经网络能否输入不同的构象信息呢?这取决于保存构象的rdkit.Chem.rdchem.Conformer对象能否转换成ConvMol/WeaveMol对象,
    如果能,在转换以后是否还有构象的信息?
    
    这个问题留到以后解决。
'''




  • 19
    点赞
  • 64
    收藏
    觉得还不错? 一键收藏
  • 9
    评论
好的,我可以为您提供一个简单的代码示例,用于搭建一个三层的RNN深度学习分类模型输入指标数为11。 首先,您需要导入PyTorch库: ```python import torch import torch.nn as nn ``` 然后,我们可以定义一个名为`RNNModel`的类来实现我们的模型: ```python class RNNModel(nn.Module): def __init__(self, input_size, hidden_size, output_size, num_layers): super(RNNModel, self).__init__() self.hidden_size = hidden_size self.num_layers = num_layers self.rnn = nn.RNN(input_size, hidden_size, num_layers, batch_first=True) self.fc = nn.Linear(hidden_size, output_size) def forward(self, x): h0 = torch.zeros(self.num_layers, x.size(0), self.hidden_size).to(device) out, _ = self.rnn(x, h0) out = self.fc(out[:, -1, :]) return out ``` 在这个模型中,我们使用了PyTorch中的`nn.RNN`模块来实现RNN层,使用`nn.Linear`模块来实现全连接层,其中`input_size`为输入的指标数,`hidden_size`为隐藏层的大小,`output_size`为输出层的大小,`num_layers`为RNN层数。 在`forward`函数中,我们首先初始一个全0的隐藏状态`h0`,然后将输入`x`和`h0`传入RNN层中,得到输出`out`,接着将`out`的最后一个时刻的输出传入全连接层`fc`中得到最终的输出。 最后,您可以实例这个模型并定义训练过程: ```python # 定义超参数 input_size = 11 hidden_size = 64 output_size = 2 num_layers = 3 learning_rate = 0.001 num_epochs = 10 # 实例模型 model = RNNModel(input_size, hidden_size, output_size, num_layers).to(device) # 定义损失函数和优器 criterion = nn.CrossEntropyLoss() optimizer = torch.optim.Adam(model.parameters(), lr=learning_rate) # 训练模型 for epoch in range(num_epochs): for i, (inputs, labels) in enumerate(train_loader): inputs = inputs.to(device) labels = labels.to(device) # 前向传播 outputs = model(inputs) loss = criterion(outputs, labels) # 反向传播和优 optimizer.zero_grad() loss.backward() optimizer.step() if (i+1) % 100 == 0: print('Epoch [{}/{}], Step [{}/{}], Loss: {:.4f}'.format(epoch+1, num_epochs, i+1, len(train_loader), loss.item())) # 测试模型 with torch.no_grad(): correct = 0 total = 0 for inputs, labels in test_loader: inputs = inputs.to(device) labels = labels.to(device) outputs = model(inputs) _, predicted = torch.max(outputs.data, 1) total += labels.size(0) correct += (predicted == labels).sum().item() print('Test Accuracy of the model on the {} test images: {} %'.format(total, 100 * correct / total)) ``` 在这个训练过程中,我们使用了PyTorch中的`nn.CrossEntropyLoss`作为损失函数,使用了`torch.optim.Adam`作为优器,同时使用了`train_loader`和`test_loader`来加载数据。在训练过程中,我们首先将输入和标签数据传入模型中进行前向传播,然后计算损失并进行反向传播和优。在测试过程中,我们计算模型在测试集上的准确率。
评论 9
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值