<SYSTEM_TASK:>
Given the following text description, write Python code to implement the functionality described below step by step
<END_TASK>
<USER_TASK:>
Description:
 Tutorial Part 23
Step1:  Make The Datasets
Let's begin by loading some molecules to work with.  We load Tox21, specifying splitter=None so everything will be returned as a single dataset.
Step3:  Because ScScore is trained on relative complexities, we want the X tensor in our dataset to have 3 dimensions (sample_id, molecule_id, features).  The molecule_id dimension has size 2 because a sample is a pair of molecules.  The label is 1 if the first molecule is more complex than the second molecule. The function create_dataset we introduce below pulls random pairs of SMILES strings out of a given list and ranks them according to this complexity measure.
In the real world you could use purchase cost, or number of reaction steps required as your complexity score.
Step4:  With our complexity ranker in place we can now construct our dataset. Let's start by randomly splitting the list of molecules into training and test sets.
Step5:  We'll featurize all our molecules with the ECFP fingerprint with chirality (matching the source paper), and will then construct our pairwise dataset using the function defined above.
Step6:  Now that we have our dataset created, let's train a ScScoreModel on this dataset.
Step7:  Model Performance
Lets evaluate how well the model does on our holdout molecules.  The SaScores should track the length of SMILES strings from never before seen molecules.
Step8:  Let's now plot the length of the smiles string of the molecule against the SaScore using matplotlib.
<ASSISTANT_TASK:>
Python Code:
!curl -Lo conda_installer.py https://raw.githubusercontent.com/deepchem/deepchem/master/scripts/colab_install.py
import conda_installer
conda_installer.install()
!/root/miniconda/bin/conda info -e
!pip install --pre deepchem
import deepchem
deepchem.__version__
Explanation: Tutorial Part 23: Synthetic Feasibility
Synthetic feasibility is a problem when running large scale enumerations.  Often molecules that are enumerated are very difficult to make and thus not worth inspection, even if their other chemical properties are good in silico.  This tutorial goes through how to train the ScScore model [1].
The idea of the model is to train on pairs of molecules where one molecule is "more complex" than the other.  The neural network then can make scores which attempt to keep this pairwise ordering of molecules.  The final result is a model which can give a relative complexity of a molecule.
The paper trains on every reaction in reaxys, declaring products more complex than reactions.  Since this training set is prohibitively expensive we will instead train on arbitrary molecules declaring one more complex if its SMILES string is longer.  In the real world you can use whatever measure of complexity makes sense for the project.
In this tutorial, we'll use the Tox21 dataset to train our simple synthetic feasibility model.
Colab
This tutorial and the rest in this sequence can be done in Google colab. If you'd like to open this notebook in colab, you can use the following link.
Setup
To run DeepChem within Colab, you'll need to run the following installation commands. This will take about 5 minutes to run to completion and install your environment. You can of course run this tutorial locally if you prefer. In that case, don't run these cells since they will download and install Anaconda on your local machine.
End of explanation
import deepchem as dc
tasks, datasets, transformers = dc.molnet.load_tox21(featurizer='Raw', splitter=None)
molecules = datasets[0].X
Explanation: Make The Datasets
Let's begin by loading some molecules to work with.  We load Tox21, specifying splitter=None so everything will be returned as a single dataset.
End of explanation
from rdkit import Chem
import random
from deepchem.feat import CircularFingerprint
import numpy as np
def create_dataset(fingerprints, smiles_lens, ds_size=100000):
    
    m1: list of np.Array
        fingerprints for molecules
    m2: list of int
        length of a molecules SMILES string
    
    returns:
        dc.data.Dataset for input into ScScore Model
        
    Dataset.X
        shape is (sample_id, molecule_id, features)
    Dataset.y
        shape is (sample_id,)
        values is 1 if the 0th index molecule is more complex
                  0 if the 1st index molecule is more complex
    
    X, y = [], []
    all_data = list(zip(fingerprints, smiles_lens))
    while len(y) < ds_size:
        i1 = random.randrange(0, len(smiles_lens))
        i2 = random.randrange(0, len(smiles_lens))
        m1 = all_data[i1]
        m2 = all_data[i2]
        if m1[1] == m2[1]:
            continue
        if m1[1] > m2[1]:
            y.append(1.0)
        else:
            y.append(0.0)
        X.append([m1[0], m2[0]])
    return dc.data.NumpyDataset(np.array(X), np.expand_dims(np.array(y), axis=1))
Explanation: Because ScScore is trained on relative complexities, we want the X tensor in our dataset to have 3 dimensions (sample_id, molecule_id, features).  The molecule_id dimension has size 2 because a sample is a pair of molecules.  The label is 1 if the first molecule is more complex than the second molecule. The function create_dataset we introduce below pulls random pairs of SMILES strings out of a given list and ranks them according to this complexity measure.
In the real world you could use purchase cost, or number of reaction steps required as your complexity score.
End of explanation
molecule_ds = dc.data.NumpyDataset(np.array(molecules))
splitter = dc.splits.RandomSplitter()
train_mols, test_mols = splitter.train_test_split(molecule_ds)
Explanation: With our complexity ranker in place we can now construct our dataset. Let's start by randomly splitting the list of molecules into training and test sets.
End of explanation
n_features = 1024
featurizer = dc.feat.CircularFingerprint(size=n_features, radius=2, chiral=True)
train_features = featurizer.featurize(train_mols.X)
train_smiles_len = [len(Chem.MolToSmiles(x)) for x in train_mols.X]
train_dataset = create_dataset(train_features, train_smiles_len)
Explanation: We'll featurize all our molecules with the ECFP fingerprint with chirality (matching the source paper), and will then construct our pairwise dataset using the function defined above.
End of explanation
model = dc.models.ScScoreModel(n_features=n_features)
model.fit(train_dataset, nb_epoch=20)
Explanation: Now that we have our dataset created, let's train a ScScoreModel on this dataset.
End of explanation
import matplotlib.pyplot as plt
%matplotlib inline
mol_scores = model.predict_mols(test_mols.X)
smiles_lengths = [len(Chem.MolToSmiles(x)) for x in test_mols.X]
Explanation: Model Performance
Lets evaluate how well the model does on our holdout molecules.  The SaScores should track the length of SMILES strings from never before seen molecules.
End of explanation
plt.figure(figsize=(20,16))
plt.scatter(smiles_lengths, mol_scores)
plt.xlim(0,80)
plt.xlabel("SMILES length")
plt.ylabel("ScScore")
plt.show()
Explanation: Let's now plot the length of the smiles string of the molecule against the SaScore using matplotlib.
End of explanation
<END_TASK>