6.1.3 Caso de estudio
Para los siguientes ejercicios usaremos una base de datos descargada de ChEMBL que contiene información sobre fármacos en fase 4 (aprobados y comercializados) con 1677 moléculas. La base de datos tiene columnas que nos informan el identificador (ID) de cada compuesto en ChEMBL, nombre, SMILES, tipo de molécula, fase clínica, si es de administración oral, parenteral o tópica, el año en que fue aprobado como fármaco y su indicación terapéutica. Utilizaremos Google Colab para este análisis.
Importación de librerías a utilizar y cargar base de datos
Comenzamos con la instalación de la paquetería RDKit:
Para el manejo de nuestra base de datos y la visualización, importamos paqueterías y módulos necesarios:
Con las paqueterías necesarias en nuestro notebook, ahora cargamos el archvo .xlsx con Pandas
, el cual contiene la base de datos a analizar:
A partir de aquí estaremos trabajando con el dataframe (estructura de datos en Python) llamado "df". El código nos mostrará el número de filas y columnas en la tabla, además de imprimir los datos del dataframe. Podemos darle un nombre distinto si cambiamos las letras antes del igual en la instrucción anterior, si este nombre se modifica también debe cambiarse en el resto del código.
Toma en cuenta que estamos utilizando la función "read_excel" de Pandas
, si tienes una base de datos en un formato distinto sólo hace falta cambiar esta función por la correspondiente de la paquetería.
La base de datos a analizar: "chembl_fases_curada.xlsx" se encuentra disponible para descargar al dar click en el nombre del archivo. Después de la descarga cargar el archivo.
Escribimos los siguientes comandos en la terminal para tener información sobre las columnas y estadística básica sobre los datos numéricos:
Con estos pasos iniciales comenzamos a tener idea sobre los datos en nuestra base, continuamos con el cálculo de descriptores con RDKit.
Cálculo de descriptores
Antes de calcular descriptores, es necesario tener una nueva columna con objetos tipo "Mol", con esto la paquetería RDKit interpreta los datos como una molécula en lugar de una cadena de texto o string de la columna de SMILES:
Después del cálculo, se mostrarán las primeras dos filas del dataframe con la nueva columna "ROMol":
Ahora calculamos nuestro primer descriptor, la masa molar exacta:
Con la fracción de código df["MW"]
le indicamos a Python que cree una nueva columna llamada "MW"
en el dataframe df
. Con el resto del código, Python aplicará la función ExactMolWt
de RDKit a la columna "ROMol"
. Al cambiar el descriptor de RDKit a calcular tendremos distintos descriptores:
Con esta última celda tendremos nueve descriptores basados en propiedades fisicoquímicas para cada una de las moléculas en nuestra base de datos. A continuación, comenzaremos a analizar nuestros datos, con estas nuevas columnas de descriptores visualizaremos distintos gráficos de una variable.
Histogramas
En primer lugar, graficaremos un histograma de los enlaces rotables de los fármacos de administración parenteral. Para esto tendremos que seleccionar primero aquellos fármacos en nuestra base de datos con valor True (1) en la columna "parenteral" del dataframe. Con estos datos seleccionados graficamos con la paquetería de Seaborn:
Primero, el código selecciona las filas que corresponden a los fármacos parenterales con el uso de la expresión booleana df['parenteral']== 1
. A continuación, el dataframe resultante se asigna a la variable df_parenteral
.
Luego, el método .histplot
de Seaborn se utiliza para trazar el histograma. El eje x del histograma se establece en "RotBonds"
, una columna que representa el número de enlaces rotables en cada molécula. El dataframe se pasa como argumento data
.
El código también establece el título del histograma, los títulos de los ejes y el tamaño de las etiquetas de los ejes utilizando los métodos .axes.set_title()
, .set_xlabel()
, .set_ylabel()
y .tick_params()
, respectivamente.
Una cosa interesante a mencionar es que la biblioteca Seaborn utiliza por defecto un método llamado kdeplot
para trazar histogramas, que dibuja una estimación de la densidad de probabilidad en lugar de contar el número de observaciones en cada bin. Sin embargo, en este caso, el método histplot
se utiliza con el argumento predeterminado element="bars"
, lo que hace que el gráfico tenga barras en lugar de una línea suave.
Una alternativa a Seaborn para trazar histogramas es la biblioteca Matplotlib, que también ofrece la función hist()
. Sin embargo, Seaborn tiene la ventaja de tener una interfaz más fácil de usar y visualizaciones más atractivas de manera predeterminada.
También es posible analizar todas las variables en un mismo gráfico. En este caso se muestra la distribución de los valores para los diferentes descriptores de la base de compuestos de administración parenteral.
Se utiliza el método .hist()
de Pandas para graficar histogramas de todas las variables numéricas de la base de datos en una sola figura. El argumento figsize=(12,12) establece el tamaño de la figura en 12x12 pulgadas. Además, se establece el color de los histogramas con el argumento color="slateblue"
. Finalmente, plt.show()
muestra la figura.
Es importante tener en cuenta que al visualizar todas las variables en un mismo gráfico se puede tener una idea general de la distribución de los datos, pero también puede resultar difícil de interpretar. En algunos casos, puede ser útil analizar variables específicas de forma individual para obtener una comprensión más detallada de su distribución y comportamiento.
Gráficos de caja (boxplots)
Continuaremos el ejemplo graficando boxplots de acuerdo con la vía de administración. Crearemos una nueva columna nombrada como "Via_admon"
para especificar la vía de administración de cada molécula, de acuerdo con las condiciones impuestas. Esto se hará de manera similar a la creación de df_parenteral
en la sección de histogramas:
Usaremos la nueva columna "Via_admon" para el eje x del boxplot y el descriptor deseado en el eje y. Por ejemplo, para la masa molar exacta:
El boxplot permite visualizar la distribución del descriptor de acuerdo con la vía de administración. También es posible comparar la mediana, el rango intercuartil y los valores atípicos u outliers. También podemos graficar sin los valores atípicos:
El gráfico se ha generado utilizando sns.boxplot()
de la librería Seaborn, que toma como argumentos el nombre de la columna que contiene las etiquetas para el eje x, en este caso "Via_admon"
, y el nombre de la columna que contiene los datos para el eje y, en este caso "MW"
, y finalmente la base de datos a utilizar, df
. El objeto que devuelve la función es un eje de Matplotlib, que se utiliza para personalizar el gráfico, por ejemplo, estableciendo el título del gráfico y de los ejes, ajustando el tamaño de la figura y guardando el gráfico en un archivo.
También es posible graficar boxplots conjuntos para todas las variables. Por ejemplo, con el siguiente código graficamos los descriptores de los fármacos de administración oral:
Como resultado tendremos mucha variación en la escala del gráfico. Esto podemos corregirlo con el siguiente código:
En el código anterior, se vuelven a graficar los boxplots con la función sns.boxplot()
. Luego, se establece la escala del eje x en escala logarítmica con set_xscale()
. Se especifica el rango de valores del eje x con axis()
, que establece el valor mínimo (xmin
) y máximo (xmax
) del eje x. Finalmente, se ajusta el tamaño de la figura con plt.gcf().set_size_inches()
. Todo esto se hace para mejorar la visualización de los boxplots de las variables, cuyas escalas varían significativamente.
Como podemos observar, las medias de los datos varían mucho. Esto ocurre porque los datos están en diferentes escalas, lo que significa que se utilizan diferentes unidades para medir las diferentes características. Para este ejemplo, la base de datos va a ser normalizada con ayuda de la librería Scikit-learn, la cual cuenta con un módulo llamado preprocessing que proporciona las instrucciones necesarias para normalizar un conjunto de datos. Detalles sobre el código en el Colab, enlace disponible al final de esta sección.
Diagramas de violín (violinplots)
También podemos analizar cada descriptor con un violinplot, utilizando los datos de los fármacos orales, por ejemplo:
Podemos agregar gráficos para complementar nuestra visualización como en este caso. Utilizamos sns.stripplot
para agregar puntos en la gráfica de violín, cada punto representa una molécula; de esta forma podemos tener una idea de la cantidad de datos cuando comparamos distintos grupos.
Otro ejemplo con el descriptor CSP3 por vía de administración:
La variable 'Via_admon' se representa en el eje x y se trata como una variable categórica, mientras que la variable 'CSP3' se representa en el eje y y se trata como una variable continua. El argumento 'palette' se utiliza para especificar la paleta de colores que se utilizará en el gráfico.
Análisis de correlación
Otro aspecto importante para entender nuestros datos es estudiar la correlación entre las variables. Si queremos, por ejemplo, ver la correlación entre el logP y la TPSA, podemos graficar:
El código anterior utiliza la función jointplot
de la biblioteca Seaborn para mostrar la relación entre las variables en un gráfico de dispersión con histogramas marginales. La opción kind='reg'
agrega una línea de regresión lineal para mostrar la tendencia en la relación entre ambas variables. La línea se ajusta según la ecuación y = mx + b, donde "y" es la variable dependiente (TPSA), "x" es la variable independiente (SlogP), "m" es la pendiente de la línea y "b" es el intercepto.
Graficaremos ahora una matriz de correlación con la función pairplot()
con las seis columnas de la base de datos: "logP", "TPSA", "MW", "RotBonds", "HBD" y "HBA". Para cada par de variables, se traza un gráfico de dispersión y un histograma de cada variable en la diagonal. Los gráficos de dispersión pueden ser personalizados mediante el argumento kind
, que puede ser "scatter", "reg" o "kde" (entre otros). Se utiliza el argumento corner
para ocultar la mitad superior de la matriz, ya que los gráficos en esa sección son una repetición de los de la mitad inferior:
En el caso de este conjunto de datos, podemos observar, por ejemplo, que hay una correlación positiva entre "TPSA" y las variables "MW", "HBD" y "HBA". Esto coincide con lo que esperaríamos, ya que los átomos contados como aceptores y/o donadores de puente de hidrógeno (N, O) también son considerados para el cálculo de TPSA. Al mismo tiempo, los átomos de nitrógeno y oxígeno contribuirán a aumentar la masa molar de las moléculas.
Calcularemos ahora el coeficiente de correlación de Pearson:
En el código proporcionado, la función get_corr
toma tres argumentos: col1
y col2
que corresponden a los nombres de las columnas de las dos variables que se van a comparar, y temp_df
que es el dataframe que contiene esas variables. Se utiliza la función pearsonr
del módulo scipy.stats
para calcular el coeficiente de correlación de Pearson y el valor p. Luego imprime en pantalla el valor de la correlación y el valor p.
Es importante tener en cuenta que la correlación no implica causalidad. Dos variables pueden estar altamente correlacionadas pero no necesariamente estar relacionadas causalmente. Por lo tanto, se requiere un análisis más profundo para determinar si una correlación observada implica una relación causal.
Con el coeficiente de correlación de Pearson podemos crear también un dataframe para cada par de columnas, usando la función df.corr()
y graficar un mapa de calor con los coeficientes resultantes:
Se establece el parámetro annot
como False, lo que significa que los valores de la matriz de correlación no se muestran en el mapa de calor. Si quisieras que se muestren los valores, simplemente debes cambiar el parámetro a True
. El parámetro square
está establecido como True, lo que asegura que el mapa de calor se ajuste a un cuadrado perfecto.
Cuando se comparan varias variables al mismo tiempo es difícil comprender cómo se comportan los datos. Así que podríamos añadir al heatmap los coeficientes de cada comparación y trazar sólo la matriz de correlación triangular inferior (ya que es un gráfico simétrico, y la información del triángulo superior es redundante):
Observamos que las correlaciones inferidas con el pairplot tienen valores de Pearson mayores a 0.5, siendo la más alta la existente entre TPSA
y HBA
(0.87), todas ellas positivas. Esto implica que al aumentar el valor de TPSA
también aumenta el de MW
, HBA
y HBD
.
Núcleos base o scaffolds
En quimioinformática, también es común analizar las bases de datos con el cálculo de núcleos base (scaffolds o frameworks) de las moléculas presentes. Aunque existen varias definiciones, utilizaremos la implementación de Bemis-Murcko en RDKit para este ejemplo (Bemis y Murcko 1996):
Con la primera celda de código obtendremos el SMILES del scaffold para cada molécula. Con la segunda celda añadiremos una nueva columna tipo "Mol" con este scaffold y lo visualizaremos. El nombre de la nueva columna lo definimos con molCol
y los datos del SMILES de Murcko con smilesCol
.
Seguimos trabajando con los datos en el código (ver Colab) hasta obtener la siguiente visualización:
Raincloud plots
Finalizaremos nuestro análisis con gráficas de nube. Como primer paso, añadiremos a nuestro Colab otro archivo con datos de inhibidores contra el blanco farmacéutico DNMT1:
El archivo puede descargarse desde: https://drive.google.com/file/d/1X5T9mDB9Ox4sHKPnnYCDMfUX107222bK/view?usp=sharing
Concatenamos esta nueva base de datos con la anterior siguiendo los pasos del Colab, calcularemos para todas las moléculas dos nuevos descriptores: Quantitative Estimate of Drug-Likeness (QED) (Bickerton et. al. 2012) y Synthetic Accesibility Score (SAscore) (Ertl y Schuffenhauer 2009). Finalizamos con las gráficas de nube (más detalles para las celdas de código en Colab):
La base de datos completa con los valores de QED y SAscore "DATA.csv" puede descargarse de: https://drive.google.com/file/d/1QhsQGqjX8wXnG3uYwdPMeWt004qbkOr2/view?usp=sharing
Para saber más:
Bemis GW, Murcko MA (1996). The Properties of Known Drugs. 1. Molecular Frameworks. J. Med. Chem. 39:2887–2893. doi: 10.1021/jm9602928.
Bickerton G, Paolini G, Besnard J, Muresan S, Hopkins AL (2012). Quantifying the chemical beauty of drugs. Nature Chem. 4:90–98. doi:10.1038/nchem.1243.
Color Guide to seaborn Palettes. https://medium.com/@morganjonesartist/color-guide-to-seaborn-palettes-da849406d44f Fecha de acceso: Enero de 2024.
Ertl P, Schuffenhauer A (2009). Estimation of synthetic accessibility score of drug-like molecules based on molecular complexity and fragment contributions. J. Cheminform. doi:10.1186/1758-2946-1-8.
Exploratory Data Analysis With mols2grid and Bemis-Murcko Frameworks. https://practicalcheminformatics.blogspot.com/2021/10/exploratory-data-analysis-with.html Fecha de acceso: Enero de 2024.
Scikit-learn. https://scikit-learn.org/stable/index.html Fecha de acceso: Enero de 2024.
Seaborn boxplot. https://seaborn.pydata.org/generated/seaborn.boxplot.html Fecha de acceso: Enero de 2024.
Seaborn violinplot. https://seaborn.pydata.org/generated/seaborn.violinplot.html Fecha de acceso: Enero de 2024.
Standard Scaler. https://scikit-learn.org/stable/modules/generated/sklearn.preprocessing.StandardScaler.html Fecha de acceso: Enero de 2024.
Last updated