Clustering¶
Cheminformatics clustering and diversity picking behind a scikit-learn API: Taylor–Butina, sphere exclusion, MaxMin and hierarchical linkage, all on Tanimoto distance.
Warning
Euclidean distance is wrong for sparse binary fingerprints. Two molecules sharing no bits at all are “close” in Euclidean terms because they agree on the thousands of bits that are jointly zero — which carry no chemical information. Everything here uses Tanimoto/Jaccard.
Taylor–Butina¶
The standard cheminformatics clustering: no n_clusters to choose,
just a similarity cutoff, and every cluster has a real molecule at its
centre rather than an average that corresponds to nothing.
>>> from qsarkit.cluster import ButinaClustering
>>> X = demo_fingerprints(256)
>>> labels = ButinaClustering(cutoff=0.6).fit_predict(X)
>>> labels[:8].tolist()
[0, 0, 0, 0, 0, 0, 0, 1]
>>> len(set(labels.tolist()))
6
The cutoff is a Tanimoto distance, so a larger value merges more:
>>> len(set(ButinaClustering(cutoff=0.4).fit_predict(X).tolist()))
14
Sphere exclusion and hierarchical¶
>>> from qsarkit.cluster import HierarchicalClustering, SphereExclusionClustering
>>> len(set(SphereExclusionClustering(cutoff=0.6).fit_predict(X).tolist()))
6
>>> HierarchicalClustering(n_clusters=3).fit_predict(X)[-4:].tolist()
[1, 1, 2, 2]
Diversity picking¶
MaxMin selects a maximally diverse subset — the right way to choose compounds for a screening plate, or a representative subset of a large library:
>>> from qsarkit.cluster import MaxMinPicker
>>> MaxMinPicker(n_to_pick=4, seed_index=0).fit(X).picks_.tolist()
[0, 21, 22, 8]
Each pick is the compound furthest from everything already picked, so the selection covers the space rather than clustering in its densest region — which is what a random sample would do.
API¶
Cheminformatics clustering and diversity picking with a scikit-learn API.
All estimators here follow the scikit-learn clustering protocol
(fit/fit_predict/labels_) and operate on fingerprint matrices
using Tanimoto (Jaccard) distance, which is the chemically appropriate
metric for sparse binary fingerprints.
- class qsarkit.cluster.ButinaClustering(cutoff=0.35, metric='jaccard', reordering=False)[source]¶
Bases:
BaseEstimator,ClusterMixinTaylor-Butina sphere-exclusion clustering of fingerprints.
The standard clustering algorithm of cheminformatics. Unlike k-means it needs no
n_clusters, produces deterministic results, and its single parameter (cutoff) is a chemically meaningful similarity threshold. The algorithm:Count, for every molecule, how many neighbours fall within the distance
cutoff— its “neighbour count”.Take the molecule with the largest count as a cluster centroid, and assign all of its unassigned neighbours to that cluster.
Repeat with the next-largest unassigned molecule until none remain.
Molecules that end up alone form singleton clusters, which is informative: a large singleton fraction means the library is structurally diverse (or the cutoff is too tight).
- Parameters:
cutoff (
float) – Maximum Jaccard distance for two molecules to be neighbours, i.e. a Tanimoto similarity of1 - cutoff. The 0.35 default (Tanimoto 0.65) is the customary value for ECFP4.metric (
str) –"jaccard"computes Tanimoto distances from fingerprints;"precomputed"treatsXas a square distance matrix.reordering (
bool) – If True, re-sort the remaining candidates by neighbour count after each cluster is formed (the “reordering” variant, which tends to give tighter clusters at higher cost).
- Variables:
labels (
ndarrayofshape (n_samples,)) – Cluster index of each sample, ordered by descending cluster size.cluster_centers_indices (
ndarrayofshape (n_clusters,)) – Index of the centroid molecule of each cluster.n_clusters (
int) – Number of clusters found.
Examples
>>> import numpy as np >>> X = np.array([[1, 1, 1, 0], [1, 1, 1, 1], [0, 0, 0, 1], [0, 0, 1, 1]]) >>> model = ButinaClustering(cutoff=0.5).fit(X) >>> model.n_clusters_ >= 1 True >>> model.labels_.shape (4,)
References
Butina, D. (1999). “Unsupervised Data Base Clustering Based on Daylight’s Fingerprint and Tanimoto Similarity: A Fast and Automated Way to Cluster Small and Large Data Sets.” J. Chem. Inf. Comput. Sci., 39(4), 747-750. https://doi.org/10.1021/ci9803381
Taylor, R. (1995). “Simulation Analysis of Experimental Design Strategies for Screening Random Compounds as Potential New Drugs and Agrochemicals.” J. Chem. Inf. Comput. Sci., 35(1), 59-67. https://doi.org/10.1021/ci00023a009
RDKit
rdSimDivPickers/Butinadocumentation: https://www.rdkit.org/docs/source/rdkit.ML.Cluster.Butina.html
- fit(X, y=None)[source]¶
Cluster the fingerprints (or precomputed distance matrix).
- Parameters:
X (
Union[Buffer,_SupportsArray[dtype[Any]],_NestedSequence[_SupportsArray[dtype[Any]]],complex,bytes,str,_NestedSequence[complex|bytes|str]]) – Fingerprints, or a square distance matrix whenmetric="precomputed".y (
Union[Buffer,_SupportsArray[dtype[Any]],_NestedSequence[_SupportsArray[dtype[Any]]],complex,bytes,str,_NestedSequence[complex|bytes|str],None]) – Present for scikit-learn API compatibility.
- Returns:
The fitted estimator.
- Return type:
- fit_predict(X, y=None)[source]¶
Fit and return
labels_.- Parameters:
X (
Union[Buffer,_SupportsArray[dtype[Any]],_NestedSequence[_SupportsArray[dtype[Any]]],complex,bytes,str,_NestedSequence[complex|bytes|str]])y (
Union[Buffer,_SupportsArray[dtype[Any]],_NestedSequence[_SupportsArray[dtype[Any]]],complex,bytes,str,_NestedSequence[complex|bytes|str],None])
- Returns:
Cluster labels.
- Return type:
- class qsarkit.cluster.SphereExclusionClustering(cutoff=0.35, metric='jaccard')[source]¶
Bases:
BaseEstimator,ClusterMixinSphere-exclusion clustering (RDKit
LeaderPickersemantics).Greedily selects “leader” molecules such that no two leaders are within
cutoffdistance of each other, then assigns every remaining molecule to its nearest leader. Unlike Butina it does not need the full neighbour-count pass, so it scales to very large libraries, and it guarantees a minimum inter-centroid distance — which is what makes it the usual choice for picking a diverse screening subset.- Parameters:
cutoff (
float) – Minimum Jaccard distance between any two leaders.metric (
str) – Distance source, as inButinaClustering.
- Variables:
labels (
ndarrayofshape (n_samples,)) – Cluster assignment of each sample.cluster_centers_indices (
ndarrayofshape (n_clusters,)) – Indices of the selected leaders.n_clusters (
int) – Number of leaders selected.
Examples
>>> import numpy as np >>> X = np.array([[1, 1, 0, 0], [1, 1, 0, 1], [0, 0, 1, 1]]) >>> model = SphereExclusionClustering(cutoff=0.5).fit(X) >>> model.labels_.shape (3,)
References
Hudson, B. D. et al. (1996). “Parameter Based Methods for Compound Selection from Chemical Databases.” Quant. Struct.-Act. Relat., 15(4), 285-289. https://doi.org/10.1002/qsar.19960150402
Gobbi, A. & Lee, M.-L. (2003). “DISE: Directed Sphere Exclusion.” J. Chem. Inf. Comput. Sci., 43(1), 317-323. https://doi.org/10.1021/ci025554v
RDKit
rdSimDivPickers.LeaderPickerdocumentation: https://www.rdkit.org/docs/source/rdkit.SimDivFilters.rdSimDivPickers.html
- fit(X, y=None)[source]¶
Select leaders and assign every sample to its nearest one.
- Parameters:
X (
Union[Buffer,_SupportsArray[dtype[Any]],_NestedSequence[_SupportsArray[dtype[Any]]],complex,bytes,str,_NestedSequence[complex|bytes|str]])y (
Union[Buffer,_SupportsArray[dtype[Any]],_NestedSequence[_SupportsArray[dtype[Any]]],complex,bytes,str,_NestedSequence[complex|bytes|str],None])
- Returns:
The fitted estimator.
- Return type:
- class qsarkit.cluster.MaxMinPicker(n_to_pick=10, metric='jaccard', seed_index=None)[source]¶
Bases:
BaseEstimatorMaxMin diverse-subset selection (RDKit
MaxMinPickersemantics).Iteratively picks the molecule whose minimum distance to the already picked set is largest, producing a maximally spread-out subset. This is the standard way to choose a diverse plate from a large library, and the diversity-sampling primitive used by
qsarkit.active_learning.- Parameters:
- Variables:
picks (
ndarrayofshape (n_to_pick,)) – Indices of the selected molecules, in selection order.min_distances (
ndarrayofshape (n_to_pick,)) – The MaxMin distance achieved at each pick — a monotonically non-increasing diversity profile of the selection.
Examples
>>> import numpy as np >>> X = np.array([[1, 1, 0, 0], [1, 1, 0, 0], [0, 0, 1, 1]]) >>> picker = MaxMinPicker(n_to_pick=2).fit(X) >>> len(picker.picks_) 2
References
Ashton, M. et al. (2002). “Identification of Diverse Database Subsets using Property-Based and Fragment-Based Molecular Descriptions.” Quant. Struct.-Act. Relat., 21(6), 598-604. https://doi.org/10.1002/qsar.200290002
Higgs, R. E. et al. (1997). “A Genetic Algorithm Approach to Similarity-Based Compound Selection.” J. Chem. Inf. Comput. Sci., 37(5), 861-870. https://doi.org/10.1021/ci9702858
RDKit
rdSimDivPickers.MaxMinPickerdocumentation: https://www.rdkit.org/docs/source/rdkit.SimDivFilters.rdSimDivPickers.html
- fit(X, y=None)[source]¶
Select the diverse subset.
- Parameters:
X (
Union[Buffer,_SupportsArray[dtype[Any]],_NestedSequence[_SupportsArray[dtype[Any]]],complex,bytes,str,_NestedSequence[complex|bytes|str]])y (
Union[Buffer,_SupportsArray[dtype[Any]],_NestedSequence[_SupportsArray[dtype[Any]]],complex,bytes,str,_NestedSequence[complex|bytes|str],None])
- Returns:
The fitted picker.
- Return type:
- class qsarkit.cluster.HierarchicalClustering(n_clusters=2, linkage='average', distance_threshold=None)[source]¶
Bases:
BaseEstimator,ClusterMixinAgglomerative clustering on Tanimoto distances.
A thin wrapper that computes the Jaccard distance matrix and hands it to scikit-learn’s
AgglomerativeClusteringwithmetric="precomputed", so that hierarchical clustering can be used on fingerprints with the chemically correct distance. Ward linkage is not available for precomputed distances; use"average"(the default here, equivalent to RDKit’s UPGMA option),"complete"or"single".- Parameters:
- Variables:
labels (
ndarrayofshape (n_samples,)) – Cluster labels.n_clusters (
int) – Number of clusters found.
Examples
>>> import numpy as np >>> X = np.array([[1, 1, 0, 0], [1, 1, 0, 0], [0, 0, 1, 1], [0, 0, 1, 1]]) >>> model = HierarchicalClustering(n_clusters=2).fit(X) >>> model.n_clusters_ 2
References
Sokal, R. R. & Michener, C. D. (1958). “A Statistical Method for Evaluating Systematic Relationships” (UPGMA). Univ. Kansas Sci. Bull., 38, 1409-1438.
Downs, G. M. & Barnard, J. M. (2002). “Clustering Methods and Their Uses in Computational Chemistry.” Rev. Comput. Chem., 18, 1-40. https://doi.org/10.1002/0471433519.ch1
scikit-learn
AgglomerativeClusteringdocumentation: https://scikit-learn.org/stable/modules/generated/sklearn.cluster.AgglomerativeClustering.html
- fit(X, y=None)[source]¶
Cluster fingerprints by agglomerative linkage on Tanimoto distance.
- Parameters:
X (
Union[Buffer,_SupportsArray[dtype[Any]],_NestedSequence[_SupportsArray[dtype[Any]]],complex,bytes,str,_NestedSequence[complex|bytes|str]])y (
Union[Buffer,_SupportsArray[dtype[Any]],_NestedSequence[_SupportsArray[dtype[Any]]],complex,bytes,str,_NestedSequence[complex|bytes|str],None])
- Returns:
The fitted estimator.
- Return type:
References¶
Butina, D. (1999). “Unsupervised Data Base Clustering Based on Daylight’s Fingerprint and Tanimoto Similarity.” J. Chem. Inf. Comput. Sci., 39(4), 747-750. doi:10.1021/ci9803381
Taylor, R. (1995). “Simulation Analysis of Experimental Design Strategies for Screening Random Compounds.” J. Chem. Inf. Comput. Sci., 35(1), 59-67. doi:10.1021/ci00023a009
Ashton, M. et al. (2002). “Identification of Diverse Database Subsets using Property-Based and Fragment-Based Molecular Descriptions.” Quant. Struct.-Act. Relat., 21(6), 598-604. doi:10.1002/qsar.200290002
Willett, P. (2006). “Similarity-Based Virtual Screening Using 2D Fingerprints.” Drug Discov. Today, 11(23-24), 1046-1053. doi:10.1016/j.drudis.2006.10.005