class_docstr: Class for doing data splits based on the butina clustering of a bulk tanimoto
  fingerprint matrix.
  
  Note
  ----
  This class requires RDKit to be installed.
  
  Examples
  --------
  >>> import deepchem as dc
  >>> import numpy as np
  >>> # creation of demo data set with some smiles strings
  >>> smiles= ['C', 'CC', 'CCC', 'CCCC', 'CCCCC']
  >>> Xs = np.zeros(len(smiles))
  >>> # creation of a deepchem dataset with the smile codes in the ids field
  >>> dataset = dc.data.DiskDataset.from_numpy(X=Xs,ids=smiles)
  >>> butinasplitter = dc.splits.ButinaSplitter()
  >>> train_dataset, test_dataset = butinasplitter.train_test_split(dataset)
  >>> print(train_dataset.ids)
  ['CCCC' 'CCC' 'CCCCC' 'CC']
  >>> print(test_dataset.ids)
  ['C']
class_docstr_tok: ["Class","for","doing","data","splits","based","on","the","butina","clustering","of","a","bulk","tanimoto","fingerprint","matrix",".","Note","--","--","This","class","requires","RDKit","to","be","installed",".","Examples","--","--","--","--",">",">",">","import","deepchem","as","dc",">",">",">","import","numpy","as","np",">",">",">","#","creation","of","demo","data","set","with","some","smiles","strings",">",">",">","smiles=","[","'","C","'",",","'CC","'",",","'CCC","'",",","'CCCC","'",",","'CCCCC","'","]",">",">",">","Xs","=","np.zeros","(","len","(","smiles",")",")",">",">",">","#","creation","of","a","deepchem","dataset","with","the","smile","codes","in","the","ids","field",">",">",">","dataset","=","dc.data.DiskDataset.from_numpy","(","X=Xs",",","ids=smiles",")",">",">",">","butinasplitter","=","dc.splits.ButinaSplitter","(",")",">",">",">","train_dataset",",","test_dataset","=","butinasplitter.train_test_split","(","dataset",")",">",">",">","print","(","train_dataset.ids",")","[","'CCCC","'","'CCC","'","'CCCCC","'","'CC","'","]",">",">",">","print","(","test_dataset.ids",")","[","'","C","'","]"]
docstr: Splits internal compounds into train and validation based on the butina
  clustering algorithm. This splitting algorithm has an O(N^2) run time, where N
  is the number of elements in the dataset. The dataset is expected to be a classification
  dataset.
  
  This algorithm is designed to generate validation data that are novel chemotypes.
  Setting a small cutoff value will generate smaller, finer clusters of high similarity,
  whereas setting a large cutoff value will generate larger, coarser clusters of low similarity.
  
  Parameters
  ----------
  dataset: Dataset
      Dataset to be split.
  frac_train: float, optional (default 0.8)
      The fraction of data to be used for the training split.
  frac_valid: float, optional (default 0.1)
      The fraction of data to be used for the validation split.
  frac_test: float, optional (default 0.1)
      The fraction of data to be used for the test split.
  seed: int, optional (default None)
      Random seed to use.
  log_every_n: int, optional (default None)
      Log every n examples (not currently used).
  
  Returns
  -------
  Tuple[List[int], List[int], List[int]]
      A tuple of train indices, valid indices, and test indices.
docstr_tok: ["Splits","internal","compounds","into","train","and","validation","based","on","the","butina","clustering","algorithm",".","This","splitting","algorithm","has","an","O","(","N^2",")","run","time",",","where","N","is","the","number","of","elements","in","the","dataset",".","The","dataset","is","expected","to","be","a","classification","dataset",".","This","algorithm","is","designed","to","generate","validation","data","that","are","novel","chemotypes",".","Setting","a","small","cutoff","value","will","generate","smaller",",","finer","clusters","of","high","similarity",",","whereas","setting","a","large","cutoff","value","will","generate","larger",",","coarser","clusters","of","low","similarity",".","Parameters","--","--","--","--","--","dataset",":","Dataset","Dataset","to","be","split",".","frac_train",":","float",",","optional","(","default","0.8",")","The","fraction","of","data","to","be","used","for","the","training","split",".","frac_valid",":","float",",","optional","(","default","0.1",")","The","fraction","of","data","to","be","used","for","the","validation","split",".","frac_test",":","float",",","optional","(","default","0.1",")","The","fraction","of","data","to","be","used","for","the","test","split",".","seed",":","int",",","optional","(","default","None",")","Random","seed","to","use",".","log_every_n",":","int",",","optional","(","default","None",")","Log","every","n","examples","(","not","currently","used",")",".","Returns","--","--","--","-","Tuple","[","List","[","int","]",",","List","[","int","]",",","List","[","int","]","]","A","tuple","of","train","indices",",","valid","indices",",","and","test","indices","."]
code: def split(
      self,
      dataset: Dataset,
      frac_train: float = 0.8,
      frac_valid: float = 0.1,
      frac_test: float = 0.1,
      seed: Optional[int] = None,
      log_every_n: Optional[int] = None,
  ) -> Tuple[List[int], List[int], List[int]]:
      """
      Splits internal compounds into train and validation based on the butina
      clustering algorithm. This splitting algorithm has an O(N^2) run time, where N
      is the number of elements in the dataset. The dataset is expected to be a classification
      dataset.
  
      This algorithm is designed to generate validation data that are novel chemotypes.
      Setting a small cutoff value will generate smaller, finer clusters of high similarity,
      whereas setting a large cutoff value will generate larger, coarser clusters of low similarity.
  
      Parameters
      ----------
      dataset: Dataset
          Dataset to be split.
      frac_train: float, optional (default 0.8)
          The fraction of data to be used for the training split.
      frac_valid: float, optional (default 0.1)
          The fraction of data to be used for the validation split.
      frac_test: float, optional (default 0.1)
          The fraction of data to be used for the test split.
      seed: int, optional (default None)
          Random seed to use.
      log_every_n: int, optional (default None)
          Log every n examples (not currently used).
  
      Returns
      -------
      Tuple[List[int], List[int], List[int]]
          A tuple of train indices, valid indices, and test indices.
      """
      try:
          from rdkit import Chem, DataStructs
          from rdkit.Chem import AllChem
          from rdkit.ML.Cluster import Butina
      except ModuleNotFoundError:
          raise ImportError(
              "This function requires RDKit to be installed."
          )
  
      logger.info(
          "Performing butina clustering with cutoff of", self.cutoff
      )
      mols = []
      for ind, smiles in enumerate(dataset.ids):
          mols.append(Chem.MolFromSmiles(smiles))
      fps = [
          AllChem.GetMorganFingerprintAsBitVect(x, 2, 1024)
          for x in mols
      ]
  
      # calcaulate scaffold sets
      # (ytz): this is directly copypasta'd from Greg Landrum's clustering example.
      dists = []
      nfps = len(fps)
      for i in range(1, nfps):
          sims = DataStructs.BulkTanimotoSimilarity(fps[i], fps[:i])
          dists.extend([1 - x for x in sims])
      scaffold_sets = Butina.ClusterData(
          dists, nfps, self.cutoff, isDistData=True
      )
      scaffold_sets = sorted(scaffold_sets, key=lambda x: -len(x))
  
      train_cutoff = frac_train * len(dataset)
      valid_cutoff = (frac_train + frac_valid) * len(dataset)
      train_inds: List[int] = []
      valid_inds: List[int] = []
      test_inds: List[int] = []
  
      logger.info("About to sort in scaffold sets")
      for scaffold_set in scaffold_sets:
          if len(train_inds) + len(scaffold_set) > train_cutoff:
              if (
                  len(train_inds) + len(valid_inds) + len(scaffold_set)
                  > valid_cutoff
              ):
                  test_inds += scaffold_set
              else:
                  valid_inds += scaffold_set
          else:
              train_inds += scaffold_set
      return train_inds, valid_inds, test_inds
  
imports: import inspect
  import itertools
  import logging
  import os
  import random
  import tempfile
  from typing import Any, Dict, Iterator, List, Optional, Sequence, Tuple, Union
  import deepchem
  import numpy
  import pandas
  from deepchem.data import Dataset, DiskDataset
  from deepchem.utils import get_print_threshold
label_desc: Use image node_id 2 for calling the ButinaSplitter obj's underlying member method code with example usage: obj.split(dataset, frac_train, frac_valid, frac_test, seed, log_every_n) and returns: train_inds,  valid_inds,  test_inds