| name | molfeat-molecular-featurization |
| description | Molecular featurization hub (100+ featurizers) for ML. SMILES to fingerprints (ECFP, MACCS, MAP4), descriptors (RDKit 2D, Mordred), pretrained embeddings (ChemBERTa, GIN, Graphormer), pharmacophores. Scikit-learn compatible with parallelization/caching. For QSAR, virtual screening, similarity, and molecular DL. |
| license | Apache-2.0 |
Molfeat — Molecular Featurization Hub
Overview
Molfeat is a comprehensive Python library for molecular featurization that unifies 100+ pre-trained embeddings and hand-crafted featurizers under a scikit-learn compatible API. Convert SMILES strings into numerical representations (fingerprints, descriptors, deep learning embeddings) for QSAR modeling, virtual screening, similarity searching, and chemical space analysis.
When to Use
- Building QSAR/QSPR models requiring molecular features as input
- Virtual screening — ranking compound libraries by predicted activity
- Similarity searching against molecular databases
- Chemical space analysis — clustering, visualization, dimensionality reduction
- Deep learning on molecules using pretrained embeddings (ChemBERTa, GIN)
- Featurization pipelines integrating with scikit-learn or PyTorch
- Comparing multiple molecular representations for benchmarking
- For molecular manipulation and filtering use datamol instead; for substructure-based molecular operations use rdkit-cheminformatics
Prerequisites
uv pip install molfeat
uv pip install "molfeat[transformer]"
uv pip install "molfeat[dgl]"
uv pip install "molfeat[graphormer]"
uv pip install "molfeat[fcd]"
uv pip install "molfeat[map4]"
uv pip install "molfeat[all]"
Quick Start
from molfeat.calc import FPCalculator
from molfeat.trans import MoleculeTransformer
smiles = ["CCO", "CC(=O)O", "c1ccccc1", "CC(C)O"]
calc = FPCalculator("ecfp", radius=3, fpSize=2048)
transformer = MoleculeTransformer(calc, n_jobs=-1)
features = transformer(smiles)
print(f"Shape: {features.shape}")
transformer.to_state_yaml_file("featurizer_config.yml")
Key Concepts
Architecture: Calculator → Transformer → Store
Molfeat organizes featurization into three layers:
| Layer | Class | Purpose | Use When |
|---|
| Calculator | molfeat.calc.* | Single molecule → feature vector | Custom loops, single molecules |
| Transformer | molfeat.trans.MoleculeTransformer | Batch processing with parallelization | Datasets, scikit-learn pipelines |
| Store | molfeat.store.ModelStore | Discovery and loading of pretrained models | Finding available featurizers |
Calculators are callable: calc("CCO") returns a numpy array. Transformers wrap calculators for batch processing: transformer(smiles_list) returns a 2D array. Pretrained transformers (PretrainedMolTransformer) add batched GPU inference and caching.
Featurizer Selection Guide
| Task | Recommended | Dimensions | Speed |
|---|
| General QSAR | ecfp (radius=3) | 2048 | Fast |
| Scaffold similarity | maccs | 167 | Very fast |
| Large-scale screening | map4 | 1024 | Fast |
| Interpretable models | desc2D (RDKitDescriptors2D) | 200+ | Fast |
| Comprehensive descriptors | mordred | 1800+ | Medium |
| Transfer learning | ChemBERTa-77M-MLM | 768 | Slow* |
| Graph-based DL | gin-supervised-masking | Variable | Slow* |
| Pharmacophore | fcfp or cats2D | 2048 / 21 | Fast |
| 3D shape | usr / usrcat | 12 / 60 | Fast |
*First run slow; subsequent runs cached.
State Persistence
Save and reload exact featurizer configuration for reproducibility:
transformer.to_state_yaml_file("config.yml")
transformer.to_state_json_file("config.json")
loaded = MoleculeTransformer.from_state_yaml_file("config.yml")
Core API
1. Fingerprint Calculators
from molfeat.calc import FPCalculator
ecfp = FPCalculator("ecfp", radius=3, fpSize=2048)
fp = ecfp("CCO")
print(f"ECFP shape: {fp.shape}")
maccs = FPCalculator("maccs")
fp = maccs("c1ccccc1")
print(f"MACCS shape: {fp.shape}")
ecfp_count = FPCalculator("ecfp-count", radius=3, fpSize=2048)
map4 = FPCalculator("map4")
print(f"MAP4 shape: {map4('CCO').shape}")
Available fingerprint types: ecfp, fcfp, maccs, rdkit, avalon, pattern, layered, atompair, topological, map4, secfp, erg, estate (and count variants with -count suffix).
2. Descriptor Calculators
from molfeat.calc import RDKitDescriptors2D, MordredDescriptors
desc2d = RDKitDescriptors2D()
descriptors = desc2d("CCO")
print(f"2D descriptors: {len(descriptors)}")
print(f"Feature names: {desc2d.columns[:5]}")
mordred = MordredDescriptors()
descriptors = mordred("c1ccccc1O")
print(f"Mordred descriptors: {len(descriptors)}")
3. Pharmacophore & Shape Calculators
from molfeat.calc import CATSCalculator, USRDescriptors
cats = CATSCalculator(mode="2D", scale="raw")
descriptors = cats("CC(C)Cc1ccc(C)cc1C")
print(f"CATS shape: {descriptors.shape}")
usr = USRDescriptors()
shape = usr("CC(=O)Oc1ccccc1C(=O)O")
print(f"USR shape: {shape.shape}")
4. Batch Processing with Transformers
from molfeat.trans import MoleculeTransformer, FeatConcat
from molfeat.calc import FPCalculator
smiles = ["CCO", "CC(=O)O", "c1ccccc1", "CC(C)O", "CCCC"]
transformer = MoleculeTransformer(FPCalculator("ecfp"), n_jobs=-1)
features = transformer(smiles)
print(f"Batch shape: {features.shape}")
concat = FeatConcat([
FPCalculator("maccs"),
FPCalculator("ecfp")
])
combo_transformer = MoleculeTransformer(concat, n_jobs=-1)
combo_features = combo_transformer(smiles)
print(f"Combined shape: {combo_features.shape}")
safe_transformer = MoleculeTransformer(
FPCalculator("ecfp"), n_jobs=-1,
ignore_errors=True, verbose=True
)
features = safe_transformer(["CCO", "invalid", "c1ccccc1"])
5. Pretrained Model Embeddings
from molfeat.trans.pretrained import PretrainedMolTransformer
chemberta = PretrainedMolTransformer("ChemBERTa-77M-MLM", n_jobs=-1)
embeddings = chemberta(["CCO", "CC(=O)O", "c1ccccc1"])
print(f"ChemBERTa shape: {embeddings.shape}")
gin = PretrainedMolTransformer("gin-supervised-masking", n_jobs=-1)
graph_emb = gin(["CCO", "CC(=O)O"])
print(f"GIN shape: {graph_emb.shape}")
6. ModelStore — Discovering Featurizers
from molfeat.store.modelstore import ModelStore
store = ModelStore()
print(f"Total available: {len(store.available_models)}")
results = store.search(name="ChemBERTa")
for model in results:
print(f" {model.name}: {model.description}")
card = store.search(name="ChemBERTa-77M-MLM")[0]
card.usage()
transformer = store.load("ChemBERTa-77M-MLM")
Common Workflows
Workflow 1: QSAR Model Building
from molfeat.calc import FPCalculator
from molfeat.trans import MoleculeTransformer
from sklearn.ensemble import RandomForestRegressor
from sklearn.model_selection import cross_val_score
transformer = MoleculeTransformer(FPCalculator("ecfp", radius=3), n_jobs=-1)
X = transformer(smiles_train)
print(f"Features shape: {X.shape}")
model = RandomForestRegressor(n_estimators=100)
scores = cross_val_score(model, X, y_train, cv=5, scoring='r2')
print(f"R² = {scores.mean():.3f} ± {scores.std():.3f}")
transformer.to_state_yaml_file("production_featurizer.yml")
Workflow 2: Virtual Screening Pipeline
from sklearn.ensemble import RandomForestClassifier
transformer = MoleculeTransformer(FPCalculator("ecfp"), n_jobs=-1)
X_train = transformer(train_smiles)
clf = RandomForestClassifier(n_estimators=500, n_jobs=-1)
clf.fit(X_train, train_labels)
X_screen = transformer(screening_smiles)
predictions = clf.predict_proba(X_screen)[:, 1]
top_indices = predictions.argsort()[::-1][:1000]
top_hits = [screening_smiles[i] for i in top_indices]
print(f"Top 1000 hits selected from {len(screening_smiles)} compounds")
Workflow 3: Featurizer Benchmarking
from molfeat.calc import FPCalculator, RDKitDescriptors2D
from sklearn.metrics import roc_auc_score
featurizers = {
'ECFP': FPCalculator("ecfp"),
'MACCS': FPCalculator("maccs"),
'Descriptors': RDKitDescriptors2D(),
}
for name, calc in featurizers.items():
transformer = MoleculeTransformer(calc, n_jobs=-1)
X_train = transformer(smiles_train)
X_test = transformer(smiles_test)
clf = RandomForestClassifier(n_estimators=100)
clf.fit(X_train, y_train)
auc = roc_auc_score(y_test, clf.predict_proba(X_test)[:, 1])
print(f"{name}: AUC = {auc:.3f}")
Common Recipes
Recipe: Scikit-learn Pipeline Integration
from sklearn.pipeline import Pipeline
from sklearn.ensemble import RandomForestClassifier
pipeline = Pipeline([
('featurizer', MoleculeTransformer(FPCalculator("ecfp"), n_jobs=-1)),
('classifier', RandomForestClassifier(n_estimators=100))
])
pipeline.fit(smiles_train, y_train)
predictions = pipeline.predict(smiles_test)
Recipe: Similarity Search
from sklearn.metrics.pairwise import cosine_similarity
calc = FPCalculator("ecfp")
query_fp = calc("CC(=O)Oc1ccccc1C(=O)O").reshape(1, -1)
transformer = MoleculeTransformer(calc, n_jobs=-1)
db_fps = transformer(database_smiles)
similarities = cosine_similarity(query_fp, db_fps)[0]
top_k = similarities.argsort()[-10:][::-1]
for i in top_k:
print(f" {database_smiles[i]}: {similarities[i]:.3f}")
Recipe: Chunk Processing for Large Datasets
import numpy as np
def featurize_chunks(smiles_list, transformer, chunk_size=10000):
all_features = []
for i in range(0, len(smiles_list), chunk_size):
chunk = smiles_list[i:i+chunk_size]
features = transformer(chunk)
all_features.append(features)
print(f"Processed {min(i+chunk_size, len(smiles_list))}/{len(smiles_list)}")
return np.vstack(all_features)
Key Parameters
| Parameter | Module | Default | Description |
|---|
method | FPCalculator | — | Fingerprint type: ecfp, maccs, map4, etc. |
radius | FPCalculator | 3 | Circular fingerprint radius |
fpSize | FPCalculator | 2048 | Fingerprint bit length |
counting | FPCalculator | False | Count vector instead of binary |
n_jobs | MoleculeTransformer | 1 | Parallel workers (-1 = all cores) |
ignore_errors | MoleculeTransformer | False | Skip invalid molecules (returns None) |
verbose | MoleculeTransformer | False | Log processing details |
dtype | MoleculeTransformer | float64 | Output type (float32 for memory) |
mode | CATSCalculator | "2D" | Distance calculation mode |
scale | CATSCalculator | "raw" | Scaling: raw, num, count |
Best Practices
- Use
n_jobs=-1 for parallel processing on all CPU cores — significant speedup for batch featurization
- Start with ECFP for initial baselines — best general-purpose fingerprint before trying deep learning
- Use
ignore_errors=True for large datasets — invalid SMILES won't crash the pipeline
- Save configurations with
to_state_yaml_file() for reproducibility — recreate exact featurizer later
- Use float32 when memory matters:
MoleculeTransformer(calc, dtype=np.float32)
- Cache pretrained embeddings — first ChemBERTa/GIN inference is slow, subsequent runs use cache
- Process in chunks for datasets >100K — prevents memory exhaustion (see Recipes)
- Combine fingerprints with
FeatConcat to capture complementary molecular information
Troubleshooting
| Problem | Cause | Solution |
|---|
ValueError: unsupported featurizer | Unknown method name | Check FPCalculator supported types or use ModelStore.search() |
ImportError for pretrained model | Missing optional dependency | Install extras: pip install "molfeat[transformer]" or "molfeat[dgl]" |
None in output array | Invalid SMILES with ignore_errors=True | Filter results: [f for f in features if f is not None] |
| Memory error on large dataset | Too many molecules at once | Process in chunks of 10K-50K (see Recipes) |
| Slow pretrained model inference | First run downloads model weights | Normal — subsequent runs use cache |
| Shape mismatch in pipeline | Mixed valid/invalid molecules | Ensure ignore_errors=True and filter None before ML model |
| Reproducibility issues | Different molfeat versions | Pin version and save config: transformer.to_state_yaml_file() |
Related Skills
datamol-cheminformatics — High-level molecular manipulation (standardization, I/O, conformers)
rdkit-cheminformatics — Low-level cheminformatics (substructure, reactions, 3D)
scikit-learn — ML models consuming molfeat features
References
Bundled Resources
Main SKILL.md + 2 reference files. Original total: 1,273 lines (SKILL.md 510 + api_reference.md 429 + available_featurizers.md 334). Scripts: none. Examples: 724 lines (examples.md).
references/available_featurizers.md: Complete catalog of all 100+ featurizers organized by category — transformer models, GNNs, descriptors, fingerprints, pharmacophore, shape, scaffold, graph featurizers. Includes dimensions, dependencies, and selection guidance per category. Purely lookup-oriented content preserved as reference.
references/api_reference.md: Detailed API reference for molfeat.calc, molfeat.trans, and molfeat.store modules. Covers SerializableCalculator base class, all calculator subclasses with parameters, MoleculeTransformer methods, PretrainedMolTransformer, FeatConcat, ModelStore/ModelCard API, data type control, and PyTorch integration patterns.
Original file disposition:
SKILL.md (510 lines) → Core API modules 1-6, Key Concepts (architecture, selection guide), Quick Start, Workflows 1-3. "Choosing the Right Featurizer" → Key Concepts selection guide table. "Advanced Features" (custom preprocessing, batch processing, caching) → Recipes + Best Practices. "Common Featurizers Reference" table → Key Concepts selection guide. "Performance Tips" → Best Practices. Per-use-case disposition: QSAR Modeling → Workflow 1, Virtual Screening → Workflow 2, Similarity Search → Recipe, Chemical Space → When to Use bullet, scikit-learn Pipeline → Recipe, Featurizer Comparison → Workflow 3
references/api_reference.md (429 lines) → Migrated to new references/api_reference.md. Core patterns (FPCalculator, MoleculeTransformer, basic ModelStore) relocated to SKILL.md Core API modules 1-6. Detailed class methods, SerializableCalculator base class, PrecomputedMolTransformer, and PyTorch integration retained in reference
references/available_featurizers.md (334 lines) → Migrated to new references/available_featurizers.md. Top-level summary → Key Concepts selection guide table. Full categorized catalog retained in reference
references/examples.md (724 lines) → Fully consolidated inline: installation → Prerequisites; calculator examples → Core API 1-3; transformer examples → Core API 4; pretrained examples → Core API 5; ML integration → Workflows 1-3 + Recipes; advanced patterns (custom preprocessing, caching, chunk processing) → Recipes + Best Practices; troubleshooting → Troubleshooting table. No separate reference file needed — all content absorbed into SKILL.md sections
Retention: ~490 lines (SKILL.md) + ~170 lines (available_featurizers) + ~190 lines (api_reference) = ~850 / 1,273 original (excl. examples.md treated as consolidated) = ~67%. Including examples.md in denominator: ~850 / 1,997 = ~43%.