mlchem
mlchem is a Python cheminformatics library designed for the scientific community. It provides a comprehensive set of tools for data handling, molecule manipulation, drawing, machine learning, and plotting. The library has been tested for python 3.12, 3.13 and 3.14 (experimental).
Documentation
Available at seacunilever.github.io/mlchem.
Features
- Data Handling: Efficiently manage and process chemical data, including loading, cleaning, and transforming datasets.
- Molecule Manipulation: Tools for manipulating molecular structures, such as adding or removing atoms, modifying bonds, and generating molecular conformations.
- Pattern Recognition: An extensive list of functions to search for specific structural patterns.
- Molecule Drawing: Visualise molecules with customisable drawing options, creating high-quality images for presentations and publications.
- Machine Learning: Implement machine learning models for cheminformatics, including training, evaluating, and deploying models to predict chemical properties and activities.
- Feature Analysis and Interpretation: Interpret model features and provide insightful plots.
Architecture
Modules
chem.visualise/
- space.py: Computes and visualises datasets in a lower-dimensional space.
- simmaps.py: Generates "rdkit-like" similarity maps based on atomic importance weights.
- drawing.py: Handles the drawing of molecular structures with many customisable options.
chem.calculator/
- tools.py: Provides numerous tools for chemical calculations.
- descriptors.py: Calculates various descriptors for molecules, including RDKit and Mordred descriptors, atomic descriptors, chemotypes, fingerprints, and some quantum chemistry properties.
chem.manipulation.py
The mlchem.chem.manipulation module offers a variety of tools for creating, converting, manipulating molecular structures, generate new molecules and recognise molecular patterns.
ml.feature_selection/
- filters.py: Provides functionalities for filtering features.
- wrappers.py: Offers simplified interfaces for feature selection.
ml.modelling/
- model_interpretation.py: Provides tools for interpreting machine learning models.
- model_evaluation.py: Contains tools for evaluating machine learning models.
ml.preprocessing/
- dimensional_reduction.py: Provides functionalities for compressing dataframes using various dimensionality reduction techniques.
- feature_transformation.py: Expands features to polynomial features.
- scaling.py: Provides functionalities for scaling dataframes using different scaling techniques.
- undersampling.py: Contains techniques for handling imbalanced datasets.
Installation
To install mlchem, open your command prompt and use the following command:
pip install git+https://github.com/seacunilever/mlchem.git
When a release is published to PyPI, install with:
pip install mlchem-ul
Then import in Python as:
import mlchem
Development installation, to modify the code or contribute with some changes:
# Clone the repository
git clone https://github.com/seacunilever/mlchem
cd mlchem
# (Optional: create a virtual environment)
python -m venv _venv
# Activate on macOS/Linux:
source _venv/bin/activate
# Activate on Windows (PowerShell):
.\_venv\Scripts\Activate.ps1
# Activate on Windows (cmd.exe):
_venv\Scripts\activate.bat
# Make an editable install of mlchem from the source tree
pip install -e .
# and install requirements
pip install -r requirements.txt
Logging
mlchem emits diagnostic logs during pipeline execution (feature selection, model evaluation, data preprocessing) to help users track progress and debug issues. Logs are emitted at the INFO level by default and appear on the console.
Basic Usage
Logs appear automatically when running mlchem functions:
from mlchem.ml.feature_selection.wrappers import SequentialForwardSelection
from mlchem.metrics import get_geometric_S
sfs = SequentialForwardSelection(estimator=..., metric=get_geometric_S, ...)
sfs.fit(X_train, y_train, X_test, y_test)
# Logs appear on console: e.g., "10:35:55 - mlchem.ml.feature_selection.wrappers - INFO - SFS start: ..."
Controlling Log Level
Change the logging level to filter output (e.g., show only warnings, suppress info messages):
sfs = SequentialForwardSelection(..., log_level='WARNING')
sfs.fit(...) # Only WARNING+ logs appear
Valid log levels: DEBUG, INFO, WARNING, ERROR, CRITICAL
Post-Pipeline Inspection and File Logging
Capture logs to memory or file for later inspection without modifying function calls:
from mlchem.helper import start_logging
# Capture to console + memory
logs = start_logging(log_level='INFO', to_console=True)
sfs.fit(X_train, y_train, X_test, y_test)
print(logs.get_logs()) # View captured logs
# Capture to file + console
logs = start_logging(log_level='INFO', to_file='pipeline.log')
sfs.fit(...)
# Logs written to pipeline.log + displayed on console
# Capture to file only (silent)
logs = start_logging(to_console=False, to_file='pipeline.log')
sfs.fit(...) # Silent; logs only in file
Use this for non-interactive scripts and production environments.
Compatibility checks (Python 3.12, 3.13, 3.14)
This repository now includes a local matrix runner and CI workflow scaffold to keep cross-version support visible on every push.
For most local development, running python -m pytest -vv tests from repo root is enough. The commands in
this section are mainly for maintainers, release checks, or contributors who
want local parity with CI across multiple Python versions.
Prerequisite for all commands below: activate your project virtual environment first.
Warning policy note:
- A narrowly scoped
pytestwarning filter is used for an upstream SHAPPendingDeprecationWarning(shap.plots.colors._colors) tied to matplotlib colormap API changes. - Keep this filter temporary and remove it once SHAP resolves the upstream issue.
- To periodically audit all warnings explicitly, run:
python -m pytest -vv tests -W default
Coverage baseline (canonical: Python 3.12):
python -m pytest -vv tests --cov=mlchem --cov-config=.coveragerc --cov-branch --cov-report=term --cov-report=xml:coverage.xml
python - <<'PY'
import xml.etree.ElementTree as ET
root = ET.parse('coverage.xml').getroot()
line_pct = round(float(root.get('line-rate', 0.0)) * 100)
branch_pct = round(float(root.get('branch-rate', 0.0)) * 100)
print(f'line={line_pct}, branch={branch_pct}')
PY
python -m anybadge --label "line cov" --value <LINE_PERCENT> --file assets/coverage.svg --overwrite 50=red 60=orange 70=yellow 80=yellowgreen 90=green
python -m anybadge --label "branch cov" --value <BRANCH_PERCENT> --file assets/coverage-branch.svg --overwrite 50=red 60=orange 70=yellow 80=yellowgreen 90=green
Note: both badges (assets/coverage.svg for line coverage and assets/coverage-branch.svg for branch coverage) are refreshed automatically by GitHub CI on push (py312 job), so local regeneration is optional and mainly useful for previewing changes before pushing.
Current policy:
- Python 3.12 and 3.13 are required to pass.
- Python 3.14 is currently experimental (reported, not blocking).
Local matrix (default envs under ~/Envs)
The matrix helper expects existing Python environments (for example py312, py313, py314). If you do not use this layout, use the tox entrypoint below instead.
Run all environments in fast mode (default: no dependency reinstall):
From repository root:
python scripts/run_local_matrix.py
From scripts/ directory:
python run_local_matrix.py
On Windows, if output appears buffered/silent, use unbuffered mode:
py -u scripts/run_local_matrix.py
By default, the runner streams live progress (active env/step and pytest output).
Run all environments with full dependency reinstall + tests:
python scripts/run_local_matrix.py --full-install -- -vv tests
Strict mode (make Python 3.14 failures blocking):
python scripts/run_local_matrix.py --strict-314 -- -vv tests
Quiet mode (disable live streaming and print only summary):
python scripts/run_local_matrix.py --no-live-output -- -vv tests
tox entrypoint
You can also run the same idea via tox:
python -m pip install tox
python -m tox -e py312,py313,py314
The py314 tox environment is marked non-blocking during early adoption.
Usage
Here's some basic examples of how to use mlchem:
calculate rdkit descriptors for two molecules
from mlchem.chem.manipulation import create_molecule
from mlchem.chem.calculator import descriptors
mol1 = create_molecule('c1ccccc1CCCO')
mol2 = create_molecule('CCCCCN')
desc_df = descriptors.get_rdkitDesc([mol1, mol2],include_3D=True)
calculate chemotypes faster on larger datasets
from mlchem.chem.calculator import descriptors
smiles_list = ['CCO', 'CCN', 'COCC', 'c1ccccc1O']
# n_jobs=1 keeps serial execution (default)
# n_jobs>1 enables multi-threaded molecule processing
# n_jobs=-1 uses all available CPU cores
chemotypes = descriptors.get_chemotypes(smiles_list, n_jobs=4)
Performance note: chemotype execution now reuses per-molecule rule results and avoids repeated molecule preparation. This is especially important for large rule dictionaries and medium-to-large training sets.
control ML verbosity in notebooks and development runs
import logging
from sklearn.linear_model import LogisticRegression
from mlchem.ml.feature_selection.wrappers import (
SequentialForwardSelection,
CombinatorialSelection,
)
# Enable library logs in your notebook session
logging.basicConfig(level=logging.INFO)
sfs = SequentialForwardSelection(
estimator=LogisticRegression(),
estimator_string='lr',
metric=lambda y_true, y_pred: (y_true == y_pred).mean(),
log_level='INFO',
)
# Runtime toggle (use DEBUG for very verbose traces)
sfs.set_log_level('DEBUG')
sfs.set_log_level('WARNING')
cs = CombinatorialSelection(
estimator=LogisticRegression(),
metric=lambda y_true, y_pred: (y_true == y_pred).mean(),
log_level='INFO',
)
optional diagnostics for undersampling and y-scrambling
from mlchem.ml.preprocessing.undersampling import undersample
from mlchem.ml.modelling.model_evaluation import y_scrambling
train_balanced, test_updated = undersample(
train_set=train_df,
test_set=test_df,
class_column='class',
desired_proportion_majority=0.6,
log_level='INFO',
)
y_scrambling(
estimator=model,
train_set=X_train,
y_train=y_train,
test_set=X_test,
y_test=y_test,
metric_function=metric_fn,
n_iter=50,
plot=False,
log_level='INFO',
)
calculate fingerprints
from mlchem.chem.calculator import descriptors
smiles_list = ['CCO', 'CCN', 'CCC']
# Morgan bit-vectors (2048 bits by default)
fp_df = descriptors.get_fingerprint_df(smiles_list, fp_type='m', nBits=2048)
# Include bit info for interpretability on a single molecule
fp, bit_info = descriptors.get_fingerprint('CCO', fp_type='m', include_bit_info=True)
pattern recognition
de novo molecule generation and cleaning
show pre-defined colour palette
More examples in the examples folder.
Building the documentation
The documentation is built with Sphinx using the autodoc and myst-parser extensions. Source files live under docs/source/, build output lands in docs/build/html/, and a small post-build script (docs/_publish.py) mirrors that build into docs/ so GitHub Pages always serves the latest version.
Single-source content:
docs/source/welcome.md{include}s this README, so you only editREADME.md— never duplicate content into the welcome page.
What is tracked, what is not
Only the inputs and the published output are tracked in git:
- Tracked (do edit / commit)
docs/source/— Sphinx inputs (conf.py,*.rst,welcome.md,_static/custom.css).docs/Makefile,docs/make.bat,docs/_publish.py— build entry points.docs/.nojekyll— tells GitHub Pages to keep_static/and_sources/.docs/*.html,docs/_static/,docs/_sources/,docs/_images/,docs/objects.inv,docs/searchindex.js— the published mirror that GitHub Pages serves; updated automatically bymake htmlvia_publish.py.
- Not tracked (regenerated on every build, ignored via
.gitignore)docs/build/— Sphinx scratch output, includingbuild/html/.doctrees/andbuild/html/.buildinfoincremental-build caches.docs/*warnings*.{log,txt}— ad-hoc diagnostic logs.
Prerequisites
The documentation toolchain is part of requirements.txt. If you only want the doc deps:
pip install sphinx myst-parser
Build & publish
Run the commands from the docs/ directory (NOT from docs/source/ — source is the value of SOURCEDIR inside the Makefile / make.bat, not the working directory):
# from the repository root
cd docs
# wipe previous build artefacts (clears docs/build/)
make clean
# build HTML and automatically mirror docs/build/html/ -> docs/
make html
make html runs Sphinx and then invokes _publish.py, which:
- removes every stale published asset at the root of
docs/(everything exceptsource/,build/,Makefile,make.bat,_publish.py,.nojekyll,.gitignore); - copies the freshly built site from
docs/build/html/intodocs/; - ensures the
.nojekyllmarker is present so GitHub Pages keeps_static/and_sources/.
Then commit the regenerated files at the root of docs/ — that is what gets published. docs/build/ stays local.
If you ever build with a raw sphinx-build invocation, run the mirror step manually:
make publish
On Windows the same targets are dispatched through make.bat, so the commands work in both cmd and PowerShell as long as sphinx-build and python are on the PATH.
Common pitfalls: running
make htmlfromdocs/source/(noMakefilethere → "no rule" / "missing Makefile" error), or typingmake build(the Sphinx target ishtml;buildis the output directory, not a target).
Contributing
We welcome contributions to mlchem. Users are free to propose new functionalities, flag new bugs, fix old bugs and issue pull requests. Please consult the contribution guide on how to properly propose and submit changes.
Third-Party Dependencies
This project uses the SELFIES Python package for molecular string representations.
SELFIES is licensed under the Apache License 2.0. In accordance with its license, the relevant license is included in this repository.
This project uses and adapts code from the RDKit cheminformatics toolkit, which is licensed under the BSD 3-Clause License.
License
This project is licensed under the BSD-3 License.
Note: This project includes components licensed under the Apache License 2.0 (e.g., the SELFIES package), as well as source code taken and adapted from RDKit library.
Acknowledgements
Special thanks to the Safety, Environmental & Regulatory Science (SERS) Department at Unilever.
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file mlchem_ul-1.1.2.tar.gz.
File metadata
- Download URL: mlchem_ul-1.1.2.tar.gz
- Upload date:
- Size: 152.8 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via:
twine/7.0.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
25f14adef23391214ce56ce7a71fb18611cd5af86fcaaeac565edd42cd697e6f
|
|
| MD5 |
9a37bca97e8dcfcb5af8b207a3fedede
|
|
| BLAKE2b-256 |
ee355326e73f504d6a1b5ec6cba17e135d774b62c7f286913f904aea54987b64
|
Provenance
The following attestation bundles were made for mlchem_ul-1.1.2.tar.gz:
Publisher:
publish-pypi.yml on seacunilever/mlchem
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
mlchem_ul-1.1.2.tar.gz -
Subject digest:
25f14adef23391214ce56ce7a71fb18611cd5af86fcaaeac565edd42cd697e6f - Sigstore transparency entry: 2537257974
- Sigstore integration time:
-
Permalink:
seacunilever/mlchem@62c81cb5f36c7e1d6653b53940a9776105f3ab8f -
Branch / Tag:
refs/heads/master - Owner: https://github.com/seacunilever
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish-pypi.yml@62c81cb5f36c7e1d6653b53940a9776105f3ab8f -
Trigger Event:
workflow_run
-
Statement type:
File details
Details for the file mlchem_ul-1.1.2-py3-none-any.whl.
File metadata
- Download URL: mlchem_ul-1.1.2-py3-none-any.whl
- Upload date:
- Size: 159.4 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via:
twine/7.0.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
6393acfe9c9a633c6a7b2b895f890688342cc88af65ec6a1f92180d9e6f64400
|
|
| MD5 |
51ca34a166aec5ce633e5f0a6a32b8b1
|
|
| BLAKE2b-256 |
0adbf3fdf469cbca76c0b3d2a7b727482d621f2545910e2359c250e3e1fbe606
|
Provenance
The following attestation bundles were made for mlchem_ul-1.1.2-py3-none-any.whl:
Publisher:
publish-pypi.yml on seacunilever/mlchem
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
mlchem_ul-1.1.2-py3-none-any.whl -
Subject digest:
6393acfe9c9a633c6a7b2b895f890688342cc88af65ec6a1f92180d9e6f64400 - Sigstore transparency entry: 2537258532
- Sigstore integration time:
-
Permalink:
seacunilever/mlchem@62c81cb5f36c7e1d6653b53940a9776105f3ab8f -
Branch / Tag:
refs/heads/master - Owner: https://github.com/seacunilever
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish-pypi.yml@62c81cb5f36c7e1d6653b53940a9776105f3ab8f -
Trigger Event:
workflow_run
-
Statement type: