Getting Started¶
Installation¶
molfp requires Python 3.9+ and RDKit. RDKit is installed automatically via the rdkit PyPI package. If you're using conda, you may already have it:
Optional dependencies for graph neural networks:
Quick Start: End-to-End QSAR Workflow¶
Here's a complete workflow — from SMILES to a trained classifier with interpretable results:
import molfp
import numpy as np
# 1. Define molecules and activities
smiles = [
"CC(=O)Oc1ccccc1C(=O)O", # Aspirin
"CC(C)Cc1ccc(cc1)C(C)C(=O)O", # Ibuprofen
"OC(=O)c1ccccc1O", # Salicylic acid
"c1ccccc1", # Benzene
"CCO", # Ethanol
"CCCCCC", # Hexane
]
activities = [7.2, 6.8, 6.5, 4.0, 3.5, 3.0] # pIC50 values
# 2. Standardize SMILES
clean = molfp.preprocess(smiles)
# 3. Compute fingerprints (collision-free for clean SHAP)
fps = molfp.ecfp4(clean["smiles"], collision_free=True)
# 4. Interpret with SHAP — get chemical meaning for top features
result = molfp.interpret(
clean["smiles"], activities,
fp_type="ecfp4", metric="pchembl", collision_aware=True
)
print(f"Top driving bits: {result['top_bits'][:5]}")
# 5. Scaffold-aware split (no data leakage)
split = molfp.scaffold_split(clean["smiles"], test_size=0.3)
print(f"Train: {len(split['train_idx'])}, Test: {len(split['test_idx'])}")
# 6. Build sklearn pipeline
from sklearn.pipeline import make_pipeline
from sklearn.ensemble import RandomForestClassifier
pipe = make_pipeline(molfp.ECFPTransformer(), RandomForestClassifier())
# pipe.fit(smiles_train, y_train)
Computing Fingerprints¶
All fingerprint functions accept a single SMILES string, a list of SMILES, a pandas Series, or a DataFrame column.
import molfp
# Single molecule
fp = molfp.maccs("CCO")
# Batch — returns numpy array
fps = molfp.ecfp4(["CCO", "c1ccccc1", "CC(=O)Oc1ccccc1C(=O)O"])
# All 30 available types
for name in molfp.available():
fn, n_bits, desc = molfp.get(name)
print(f"{name:>30s} {n_bits:>5} {desc}")
Explainability¶
# Which atoms set which bits?
exp = molfp.explain("CCO", "ecfp4")
# exp[bit_index] = {"atoms": [0, 1], "radius": 2, "smiles": "CCO"}
# Chemical annotation for a bit
ann = molfp.annotate("maccs", 162)
# {"name": "Aromatic ring", "smarts": "c1ccccc1", ...}
SHAP Interpretation¶
result = molfp.interpret(smiles, activities, fp_type="ecfp4", metric="pchembl")
# result["shap_values"], result["top_bits"], result["class_drivers"]
Collision-Free Fingerprints¶
# Detect collisions
molfp.detect_collisions("c1ccccc1", "ecfp4", n_bits=1024)
# Collision-free mode (multi-hash)
fps = molfp.ecfp4(smiles, collision_free=True)
Scaffold Analysis¶
molfp.scaffold("CC(=O)Oc1ccccc1C(=O)O")
# {"murcko": "c1ccccc1", "generic": "C1CCCCC1", "name": "Benzene"}
# Scaffold-aware train/test split
result = molfp.scaffold_split(smiles, test_size=0.2)
Molecular Graphs¶
# Graph representation for GNNs
g = molfp.mol_graph("c1ccccc1", type="standard", enriched=True)
# Fixed-length vectors for sklearn
X = molfp.graph_vectors(smiles, type="standard", enriched=True)