Diseño de una red neuronal convolucional para el aprendizaje automático de cannabis Parte 1
Una bonita y brillante mañana de domingo para diseñar Redes Neuronales Convolucionales. Una CNN es una red neuronal entrenada en el uso de imágenes y pasa a través de una serie de filtros para determinar las características. Como químico orgánico, usamos nuestros ojos para diseñar estructuras, por lo que quizás este sea un enfoque de aprendizaje automático intuitivo y fragmentemos una molécula usando nuestros propios filtros internos. Parece natural probarlo.

Nuestro objetivo para esta red es saber si una molécula se comportará como el cannabis en función de su constante de unión (qué tan fuerte se une un ligando) en un receptor endocannabinoide común, CB1, un objetivo principal para el THC. La estructura cristalina fue derivada por Hua et al.
La estructura es una serie de hélices alfa en forma de zapato con el bolsillo de unión muy profundo dentro del receptor.

El THC a un receptor CB1 se puede cuantificar con una constante de inhibición, Ki, que es una indicación de cuán potente es un inhibidor. Los valores pequeños de Ki de 100 micromolar se consideran potentes.
Si tomamos una lista de inhibidores para CB1 y sus constantes de inhibición registradas en nM de este documento:
¿Podemos predecir si un nuevo compuesto cannabinoide se comportaría de manera similar a un terpeno como el THC en función de su valor constante de inhibición? Estos son algunos de los datos extraídos del artículo. Siéntete libre de agarrar más.
compounds = {
'CCCCC1=CC(=C2C3C=C(CCC3C(OC2=C1)(C)C)C)O': 36,
'CCCC1=CC(=C2C3C=C(CCC3C(OC2=C1)(C)C)C)O': 22,
'CCCCCC1=CC2=C(C3C=C(CCC3C(O2)(C)C)C)C(=C1C(=O)O)O': 620,
'CCCCCC1=CC(=C(C(=C1)O)C/C=C(\C)/CCC=C(C)C)O': 1045,
'CCCC1=CC(=C(C(=C1)O)C/C=C(\C)/CCC=C(C)C)O': 2865,
'CCCCCC1=CC(=C(C(=C1C(=O)O)O)C/C=C(\C)/CCC=C(C)C)O': 13116,
'COC1=C(C/C=C(CC/C=C(C)\C)\C)C(O)=CC(CCCCC)=C1': 10000,
'CCCCCC1=CC(=C(C(=C1)O)C2C=C(CCC2C(=C)C)C)O': 1690,
'CCCC1=CC(=C(C(=C1)O)C2C=C(CCC2C(=C)C)C)O': 14445,
'CCCCCC1=CC(=C(C(=C1C(=O)O)O)C2C=C(CCC2C(=C)C)C)O': 626,
}

Vamos a poner en marcha nuestras importaciones:
import rdkit
import numpy as np
import pandas as pd
from rdkit import Chem
from rdkit.Chem import AllChem
from matplotlib import pyplot as plt
df = pd.DataFrame()
df['smiles'] = list(compounds.keys())
df['ki'] = list(compounds.values())
df["mol"] = df["smiles"].apply(Chem.MolFromSmiles)

El efecto de una resolución en la imagen puede ser donde puede dominar el espacio ocupado por diferente información.

La incrustación y resolución de su imagen es muy importante porque permite que la red neuronal abstraiga características de manera más eficiente. Así que calculamos las dimensiones y las coordenadas 2D y configuramos 4 ceros vacíos que actuarán como un almacén meta para información como el número atómico.
def chemcepterize_mol(mol, embed=10.0, res=0.2):
dimensions = int(embed*2/res)
chempcepterized_molecule = Chem.Mol(mol.ToBinary())
chempcepterized_molecule.ComputeGasteigerCharges()
AllChem.Compute2DCoords(chempcepterized_molecule)
coords = chempcepterized_molecule.GetConformer(0).GetPositions()
vector = np.zeros((dims,dims,4))
[[[0. 0. 0. 0.]
[0. 0. 0. 0.]
[0. 0. 0. 0.]
...
[0. 0. 0. 0.]
[0. 0. 0. 0.]
[0. 0. 0. 0.]]
[[0. 0. 0. 0.]
[0. 0. 0. 0.]
[0. 0. 0. 0.]
...
[0. 0. 0. 0.]
[0. 0. 0. 0.]
[0. 0. 0. 0.]]
[[0. 0. 0. 0.]
[0. 0. 0. 0.]
[0. 0. 0. 0.]
...
[0. 0. 0. 0.]
[0. 0. 0. 0.]
[0. 0. 0. 0.]]
for i,bond in enumerate(mol.GetBonds()):
bond_order = bond.GetBondTypeAsDouble()
start_atom_index = bond.GetBeginAtomIdx()
end_atom_index = bond.GetEndAtomIdx()
start_coordinates = coords[start_atom_index]
end_coordinates = coords[end_atom_index]
fractional_space = np.linspace(0,1,int(1/res*2))
for fraction in fractional_space:
coordinates = (fraction*start_coordinates + (1-fraction)*end_coordinates)
x = int(round((coordinates[0] + embed)/res))
y = int(round((coordinates[1]+ embed)/res))
vector[ x, y, 0] = bond_order
for i,atom in enumerate(cmol.GetAtoms()):
x = int(round((coords[i][0] + embed)/res))
y = int(round((coords[i][1]+ embed)/res))
vector[ x , y, 1] = atom.GetAtomicNum()
hyptype = atom.GetHybridization().real
vector[ x , y, 2] = hyptype
charge = atom.GetProp("_GasteigerCharge")
vector[ x , y, 3] = charge
return vect
def chemcepterize_mol(mol, embed=10.0, res=0.2):
dimensions = int(embed*2/res)
chempcepterized_molecule = Chem.Mol(mol.ToBinary())
chempcepterized_molecule.ComputeGasteigerCharges()
AllChem.Compute2DCoords(chempcepterized_molecule)
coords = chempcepterized_molecule.GetConformer(0).GetPositions()
vector = np.zeros((dims,dims,4))
# Bonds
for i,bond in enumerate(mol.GetBonds()):
bond_order = bond.GetBondTypeAsDouble()
start_atom_index = bond.GetBeginAtomIdx()
end_atom_index = bond.GetEndAtomIdx()
start_coordinates = coords[start_atom_index]
end_coordinates = coords[end_atom_index]
# Draw Bond A long Vector
fractional_space = np.linspace(0,1,int(1/res*2))
for fraction in fractional_space:
coordinates = (fraction*start_coordinates + (1-fraction)*end_coordinates)
x = int(round((coordinates[0] + embed)/res))
y = int(round((coordinates[1]+ embed)/res))
vector[ x, y, 0] = bond_order
# Atoms
for i,atom in enumerate(cmol.GetAtoms()):
x = int(round((coords[i][0] + embed)/res))
y = int(round((coords[i][1]+ embed)/res))
vector[ x , y, 1] = atom.GetAtomicNum()
hyptype = atom.GetHybridization().real
vector[ x , y, 2] = hyptype
charge = atom.GetProp("_GasteigerCharge")
vector[ x , y, 3] = charge
return vect
def vectorize(mol):
return chemcepterize_mol(mol, embed=12)
df["mol_image"] = df["mol"].apply(vectorize)