{ "cells": [ { "cell_type": "markdown", "id": "473e4b0b", "metadata": { "collapsed": true, "jupyter": { "outputs_hidden": true } }, "source": [ "# Molecular pipelines" ] }, { "cell_type": "markdown", "id": "9a96a2ea", "metadata": {}, "source": [ "In scikit-fingerprints, you can use scikit-learn `Pipeline` objects to create complex workflows for molecular processing. Thanks to full compatibility with scikit-learn API, we can easily build pipelines for molecular preprocessing, computing fingerprints, and further machine learning. The full pipeline still uses familiar `.fit()` and `.predict()` methods." ] }, { "cell_type": "markdown", "id": "cdd2bde5", "metadata": {}, "source": [ "### Molecular property prediction pipeline\n", "\n", "Here, we will perform molecular property prediction, i.e. graph classification in this case. We revisit the task from tutorial 1, where we used [beta-secretase 1 (BACE) dataset](https://doi.org/10.1021/acs.jcim.6b00290) from MoleculeNet benchmark.\n", "\n", "We can easily chain all relevant operations in a single pipeline.\n", "\n", "Also, note that for convenience `scaffold_train_test_split` and all fingerprints, e.g. `ECFPFingerprint` ([docs](https://scikit-fingerprints.github.io/scikit-fingerprints/modules/generated/skfp.fingerprints.ECFPFingerprint.html#skfp.fingerprints.ECFPFingerprint)) used below, can also take SMILES input. Those strings will be converted to molecules inside as necessary, since this is a very cheap operation. Whole pipeline then also takes lists of SMILES as inputs, instead of NumPy arrays, e.g. `smiles_train` instead of `X_train`." ] }, { "cell_type": "code", "execution_count": 1, "id": "a04d450a", "metadata": { "execution": { "iopub.execute_input": "2025-01-19T19:42:25.590140Z", "iopub.status.busy": "2025-01-19T19:42:25.589928Z", "iopub.status.idle": "2025-01-19T19:42:27.563889Z", "shell.execute_reply": "2025-01-19T19:42:27.563447Z", "shell.execute_reply.started": "2025-01-19T19:42:25.590128Z" }, "scrolled": true }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "AUROC: 78.25%\n" ] } ], "source": [ "from sklearn.ensemble import RandomForestClassifier\n", "from sklearn.metrics import roc_auc_score\n", "from sklearn.pipeline import make_pipeline\n", "\n", "from skfp.datasets.moleculenet import load_bace\n", "from skfp.fingerprints import ECFPFingerprint\n", "from skfp.model_selection import scaffold_train_test_split\n", "\n", "smiles_list, y = load_bace()\n", "smiles_train, smiles_test, y_train, y_test = scaffold_train_test_split(\n", " smiles_list, y, test_size=0.2\n", ")\n", "\n", "pipeline = make_pipeline(\n", " ECFPFingerprint(),\n", " RandomForestClassifier(random_state=0),\n", ")\n", "pipeline.fit(smiles_train, y_train)\n", "\n", "y_pred = pipeline.predict_proba(smiles_test)[:, 1]\n", "auroc = roc_auc_score(y_test, y_pred)\n", "\n", "print(f\"AUROC: {auroc:.2%}\")" ] }, { "cell_type": "markdown", "id": "5c0cbe25-7b26-42f6-b7e1-fca9826b7058", "metadata": {}, "source": [ "### More complex molecular property prediction pipeline\n", "\n", "We will reuse the pipeline from above, but also add a second [MACCS fingerprint](https://scikit-fingerprints.github.io/scikit-fingerprints/modules/generated/skfp.fingerprints.MACCSFingerprint.html#skfp.fingerprints.MACCSFingerprint) and concatenate it as additional features. Scikit-learn has a built-in `FeatureUnion` class for this, with `make_union` function for easy usage. As it often benefits from parallelism, we will add `n_jobs=-1` to it.\n", "\n", "Since we may have all-zero features, we will also filter them out as another step, using `VarianceThreshold` ([docs](https://scikit-learn.org/stable/modules/generated/sklearn.feature_selection.VarianceThreshold.html))." ] }, { "cell_type": "code", "execution_count": 2, "id": "86bcae00-be1b-460d-a53b-474a3ac4381a", "metadata": { "execution": { "iopub.execute_input": "2025-01-19T19:42:27.564386Z", "iopub.status.busy": "2025-01-19T19:42:27.564274Z", "iopub.status.idle": "2025-01-19T19:42:29.255981Z", "shell.execute_reply": "2025-01-19T19:42:29.255626Z", "shell.execute_reply.started": "2025-01-19T19:42:27.564376Z" } }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "AUROC: 78.49%\n" ] } ], "source": [ "from sklearn.feature_selection import VarianceThreshold\n", "from sklearn.pipeline import make_union\n", "\n", "from skfp.fingerprints import MACCSFingerprint\n", "\n", "pipeline = make_pipeline(\n", " make_union(ECFPFingerprint(), MACCSFingerprint(n_jobs=-1)),\n", " VarianceThreshold(),\n", " RandomForestClassifier(random_state=0),\n", ")\n", "pipeline.fit(smiles_train, y_train)\n", "\n", "y_pred = pipeline.predict_proba(smiles_test)[:, 1]\n", "auroc = roc_auc_score(y_test, y_pred)\n", "\n", "print(f\"AUROC: {auroc:.2%}\")" ] }, { "cell_type": "markdown", "id": "1a38ec72-6105-4331-836f-a9f2339fe6f9", "metadata": {}, "source": [ "### Pipeline for dimensionality reduction and visualization\n", "\n", "Here, we will build a visualization pipeline that uses dimensionality reduction for 2D visualization.\n", "\n", "[UMAP](https://umap-learn.readthedocs.io/en/latest/) is a particularly powerful, yet easy to use nonlinear dimensionality reduction. It requires using some distance metric, which is used for pairwise distance calculation. While scikit-fingerprints implements [distance and similarity measures](https://scikit-fingerprints.github.io/scikit-fingerprints/modules/distances.html) commonly used in chemoinformatics, like [Tanimoto distance](https://scikit-fingerprints.github.io/scikit-fingerprints/modules/generated/skfp.distances.tanimoto_binary_distance.html), UMAP also supports it directly under the name `\"jaccard\"`. Lastly, we'll plot the training and testing data with Matplotlib.\n", "\n", "Since neither UMAP, nor Matplotlib are required by `scikit-fingerprints`, we will install them separately." ] }, { "cell_type": "code", "execution_count": 3, "id": "56edf903-4473-4958-aa5c-1a61118a3f90", "metadata": { "execution": { "iopub.execute_input": "2025-01-19T19:42:29.256515Z", "iopub.status.busy": "2025-01-19T19:42:29.256397Z", "iopub.status.idle": "2025-01-19T19:42:29.909365Z", "shell.execute_reply": "2025-01-19T19:42:29.908957Z", "shell.execute_reply.started": "2025-01-19T19:42:29.256503Z" }, "scrolled": true }, "outputs": [], "source": [ "!pip install --quiet matplotlib umap-learn" ] }, { "cell_type": "code", "execution_count": 4, "id": "f07f38ea-6f8e-4551-a6c0-71859bfd4647", "metadata": { "execution": { "iopub.execute_input": "2025-01-19T19:42:29.909968Z", "iopub.status.busy": "2025-01-19T19:42:29.909812Z", "iopub.status.idle": "2025-01-19T19:42:42.406673Z", "shell.execute_reply": "2025-01-19T19:42:42.406328Z", "shell.execute_reply.started": "2025-01-19T19:42:29.909956Z" } }, "outputs": [ { "name": "stderr", "output_type": "stream", "text": [ "/home/jakub/.cache/pypoetry/virtualenvs/scikit-fingerprints-VjWItXgH-py3.9/lib/python3.9/site-packages/sklearn/utils/deprecation.py:151: FutureWarning: 'force_all_finite' was renamed to 'ensure_all_finite' in 1.6 and will be removed in 1.8.\n", " warnings.warn(\n", "/home/jakub/.cache/pypoetry/virtualenvs/scikit-fingerprints-VjWItXgH-py3.9/lib/python3.9/site-packages/umap/umap_.py:1887: UserWarning: gradient function is not yet implemented for jaccard distance metric; inverse_transform will be unavailable\n", " warn(\n", "/home/jakub/.cache/pypoetry/virtualenvs/scikit-fingerprints-VjWItXgH-py3.9/lib/python3.9/site-packages/sklearn/utils/deprecation.py:151: FutureWarning: 'force_all_finite' was renamed to 'ensure_all_finite' in 1.6 and will be removed in 1.8.\n", " warnings.warn(\n", "/home/jakub/.cache/pypoetry/virtualenvs/scikit-fingerprints-VjWItXgH-py3.9/lib/python3.9/site-packages/sklearn/utils/deprecation.py:151: FutureWarning: 'force_all_finite' was renamed to 'ensure_all_finite' in 1.6 and will be removed in 1.8.\n", " warnings.warn(\n" ] }, { "data": { "image/png": "iVBORw0KGgoAAAANSUhEUgAAAioAAAGzCAYAAAABsTylAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjkuNCwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy8ekN5oAAAACXBIWXMAAA9hAAAPYQGoP6dpAAB7RUlEQVR4nO3deVxU9frA8c8wyiaLiqyComi2mmVqViiUuVSmAmpqpl3Lbq643up3yyXN0lRssbJuaoumwqhtVmbipbSsbrZnShKi4C4IKsjM+f1xmJGBAWaA2eB5v17zgjnrM2cGzjPfVaMoioIQQgghhAvycHYAQgghhBBVkURFCCGEEC5LEhUhhBBCuCxJVIQQQgjhsiRREUIIIYTLkkRFCCGEEC5LEhUhhBBCuCxJVIQQQgjhsiRREUIIIYTLkkRFCBssWbKE9u3bo9Vq6dKlCwClpaXMnj2bqKgoPDw8GDx4sE3HjI6OZuzYsTVut2bNGjQaDVlZWTbHXVvp6eloNBrS09NNy8aOHUt0dLTDYrBVXFwccXFxzg7DZbjK+2UpDo1Gw9y5cx0ei7POK2pHEpVGyHjDK/8ICQkhPj6ebdu2Vbnf2bNn8fb2RqPR8Pvvv1e5nV6vZ/Xq1cTFxdGyZUu8vLyIjo7mwQcf5Lvvvqs2jvKPr7/+ul5fd1199tlnzJ49m1tvvZXVq1fzzDPPAPDmm2+yZMkSkpKSWLt2LdOmTXNypI51/vx55s6da5bMVOe3335j7ty5Dk246mrlypWsWbPGrudwx+viyj7++GNJRhqIJs4OQDjP/PnzadeuHYqicOzYMdasWcNdd93FBx98wD333FNp+02bNqHRaAgLC+Pdd99lwYIFlba5cOECCQkJfPLJJ/Tq1YsnnniCli1bkpWVxcaNG1m7di3Z2dlERkZWiqOiDh061O8LrqMvvvgCDw8P/vOf/+Dp6Wm2vHXr1ixfvtyJ0TnO66+/jsFgMD0/f/488+bNA7CqJOO3335j3rx5xMXF2eWb/meffVbvx1y5ciWtWrWyquSrtux1XSq+X67kwoULNGlin9vQxx9/zMsvv2wxWbHneUX9k3eqERswYAA33XST6fm4ceMIDQ1l/fr1FhOVd955h7vuuou2bduybt06i4nKrFmz+OSTT1i+fDnJyclm6+bMmWPxZl4xDld1/PhxfHx8zJIU4/LmzZs7JygnaNq0qcPOpSgKFy9exMfHx+p9Kr4/jZ0j3y9beXt7N6rzitqRqh9h0rx5c3x8fCx+08jOziYjI4P77ruP++67j0OHDrF7926zbXJycnjttde48847KyUpAFqtlpkzZ5qVptTFd999R79+/WjVqhU+Pj60a9eOf/zjH2bbGAwGVqxYwXXXXYe3tzfBwcH079/frApq9erV3H777YSEhODl5cXVV1/NK6+8YnYcjUbD6tWrKSoqMlVNGauudu7cya+//mpabqwCKSoqYsaMGURFReHl5UWnTp14/vnnsWbC8l9//ZXbb78dHx8fIiMjWbBggdXfivPy8njwwQeJjIzEy8uL8PBwBg0aZFalEB0dzT333MNnn31Gly5d8Pb25uqrr0an09V4/PJtDbKysggODgZg3rx5pmtQVZH7mjVrGDp0KADx8fGVrpkxrk8//ZSbbroJHx8fXnvtNcC69wkqt1ExtrPZuHEjCxcuJDIyEm9vb+644w4OHjxY4+uNjo7m119/ZdeuXaZ4yx//7NmzJCcnm97nDh068Nxzz1V6v9577z26du2Kv78/AQEBXHfddaxYscKq61LR888/j0aj4e+//6607vHHH8fT05MzZ84AltuGVBcLwNy5c9FoNJWObamd1NatW7n77ruJiIjAy8uLmJgYnn76afR6fZXX1Kj8ZyUrK6vaqmCjjIwMhg4dSps2bfDy8iIqKopp06Zx4cIF0zZjx47l5ZdfNp2j4jEsfUZ/+OEHBgwYQEBAAH5+ftxxxx2Vqp+Nr/+rr75i+vTpBAcH06xZM4YMGcKJEydqfL2idqREpRHLz8/n5MmTKIrC8ePHefHFFyksLOT++++vtO369etp1qwZ99xzDz4+PsTExPDuu+9yyy23mLbZtm0bpaWljB49ulZxlKfRaAgKCqpyn+PHj9O3b1+Cg4N57LHHaN68OVlZWZVutOPGjWPNmjUMGDCAhx56iNLSUjIyMvj6669NpTivvPIK11xzDffeey9NmjThgw8+YMKECRgMBiZOnAjA22+/zapVq9i7dy9vvPEGADfccANvv/02CxcupLCwkEWLFgFw1VVXoSgK9957Lzt37mTcuHF06dKFTz/9lFmzZnHkyJFqq4ny8vKIj4+ntLSUxx57jGbNmrFq1SqrSxUSExP59ddfmTx5MtHR0Rw/fpzt27eT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pEmTCA8Px9vbm7Zt27Jo0SIAoqOjARgyZAgajcb0vKLqjgFw9uxZHnroIYKDgwkICOD222/nxx9/BGDNmjXMmzePH3/80VQCtGbNmnq/RjWxa6KyaNEiunXrhr+/PyEhIQwePNgskwSIi4urVBT2z3/+055hCSGEaGz0erUkxdKkl8Zlycl2rQaq6N133+Wpp55i4cKF/P777zzzzDM8+eSTrF27FoAXXniB999/n40bN7J//37effddU0Ly7bffArB69Wpyc3NNzyuq7hgAQ4cO5fjx42zbto3vv/+eG2+8kTvuuIPTp08zfPhwZsyYwTXXXENubi65ubkMHz7crtfEErtW/ezatYuJEyfSrVs3SktLeeKJJ+jbty+//fYbzZo1M2338MMPM3/+fNNzX19fe4YlhBCiscnIqFySUp6iwOHD6nYOGhl5zpw5LF26lISyKqd27drx22+/8dprrzFmzBiys7Pp2LEjt912GxqNhrZt25r2DQ4OBqB58+aEhYVVeY7qjvHll1+yd+9ejh8/jpeXFwDPP/88W7ZsITU1lfHjx+Pn50eTJk2qPYe92TVR+eSTT8yer1mzhpCQEL7//nt69eplWu7r6+vUiyCEEKKBK9dWpF62q6OioiIyMzMZN24cDz/8sGl5aWkpgYGBAIwdO5Y777yTTp060b9/f+655x769u1r03mqO8aPP/5IYWEhQUFBZvtcuHCBzMzMOr7C+uPQxrT5+fkAtGzZ0mz5u+++yzvvvENYWBgDBw7kySefrLJUpbi4mOLiYtPzgoIC+wUshBCiYQgPr9/t6qiwsBCA119/nR49epit05ZNwnnjjTdy6NAhtm3bxueff86wYcPo06cPqampVp+numMUFhYSHh5Oenp6pf2aN29e69dW3xyWqBgMBpKTk7n11lu59tprTctHjhxJ27ZtiYiI4KeffuJf//oX+/fvR1dFo6ZFixYxb948R4UthBCiIYiNVXv3HDliuZ2KRqOuj411SDihoaFERETw119/MWrUqCq3CwgIYPjw4QwfPpykpCT69+/P6dOnadmyJU2bNkVvRZuaqo5x4403kpeXR5MmTapsjOvp6WnVOezJYYnKxIkT+eWXX/jyyy/Nlo8fP970+3XXXUd4eDh33HEHmZmZxMTEVDrO448/zvTp003PCwoKiIqKsl/gQggh3J9Wq3ZB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", "text/plain": [ "
" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "import matplotlib.pyplot as plt\n", "from umap import UMAP\n", "\n", "pipeline = make_pipeline(\n", " ECFPFingerprint(),\n", " UMAP(n_components=2, metric=\"jaccard\", n_jobs=-1),\n", ")\n", "pipeline.fit(smiles_train)\n", "\n", "X_train = pipeline.transform(smiles_train)\n", "X_test = pipeline.transform(smiles_test)\n", "\n", "plt.scatter(X_train[:, 0], X_train[:, 1], c=\"b\", label=\"Train set\")\n", "plt.scatter(X_test[:, 0], X_test[:, 1], c=\"r\", label=\"Test set\")\n", "plt.title(\"BACE scaffold split train-test visualization\")\n", "plt.legend()\n", "plt.show()" ] }, { "cell_type": "markdown", "id": "2fec1dd0-d7d2-451f-a359-4800bdb5155f", "metadata": {}, "source": [ "### Pipelines with conformational fingerprints\n", "\n", "Some fingerprints, like [RDF fingerprint](https://scikit-fingerprints.github.io/scikit-fingerprints/modules/generated/skfp.fingerprints.RDFFingerprint.html), are based on the 3D (spatial) structure of a molecule conformer. They can be easily generated in scikit-fingerprints with [ConformerGenerator](https://scikit-fingerprints.github.io/scikit-fingerprints/modules/generated/skfp.preprocessing.ConformerGenerator.html), which uses ETKDGv3 algorithm underneath. This information is saved as a molecule attribute, and such molecules can be vectorized with both conformational fingerprints and regular ones. Note that conformer generation is hard, and can sometimes fail. It is also quite computationally expensive, and using parallelization is very useful.\n", "\n", "We will use both conformational RDF fingerprint and topological (\"flat\") ECFP fingerprint here, concatenated to create a more rich feature space for classification. Since they create features with really different value ranges, we'll add min-max scaling. This is particularly important for linear classifiers and anything not based on decision trees. To make things more interesting, we will use logistic regression, the most popular linear model." ] }, { "cell_type": "code", "execution_count": 5, "id": "bc3eddf72d1147fe", "metadata": { "execution": { "iopub.execute_input": "2025-01-19T19:42:42.407200Z", "iopub.status.busy": "2025-01-19T19:42:42.407011Z", "iopub.status.idle": "2025-01-19T19:42:57.918771Z", "shell.execute_reply": "2025-01-19T19:42:57.918385Z", "shell.execute_reply.started": "2025-01-19T19:42:42.407177Z" } }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "AUROC: 78.22%\n" ] } ], "source": [ "from sklearn.linear_model import LogisticRegression\n", "from sklearn.preprocessing import MinMaxScaler\n", "\n", "from skfp.fingerprints import RDFFingerprint\n", "from skfp.preprocessing import ConformerGenerator, MolFromSmilesTransformer\n", "\n", "pipeline = make_pipeline(\n", " MolFromSmilesTransformer(),\n", " ConformerGenerator(n_jobs=-1),\n", " make_union(RDFFingerprint(), ECFPFingerprint()),\n", " MinMaxScaler(),\n", " LogisticRegression(max_iter=1000, random_state=0),\n", ")\n", "pipeline.fit(smiles_train, y_train)\n", "\n", "y_pred = pipeline.predict_proba(smiles_test)[:, 1]\n", "auroc = roc_auc_score(y_test, y_pred)\n", "\n", "print(f\"AUROC: {auroc:.2%}\")" ] } ], "metadata": { "kernelspec": { "display_name": "Python 3 (ipykernel)", "language": "python", "name": "python3" }, "language_info": { "codemirror_mode": { "name": "ipython", "version": 3 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", "version": "3.9.21" } }, "nbformat": 4, "nbformat_minor": 5 }