Skip to main content

BenchAudit

CI Publish to PyPI Python 3.10+ Docs Website ChemRxiv preprint License: GPL v3

BenchAudit is a lightweight pipeline for auditing molecular property and drug–target interaction benchmarks. It standardizes SMILES strings, checks split hygiene, surfaces label conflicts and activity cliffs, and can run simple baseline models. Outputs are machine‑readable summaries and drill‑down tables you can inspect or feed into other tools.

Features

  • Config‑driven analysis of tabular, TDC, Polaris, and DTI datasets.
  • SMILES standardization with optional REOS alerts and configurable fingerprint settings.
  • Split hygiene reports: duplicates, cross‑split contamination, and nearest‑neighbor similarity.
  • Conflict and activity‑cliff detection for classification and regression tasks.
  • DTI extras: sequence normalization, cross‑split pair conflicts, and EMBOSS stretcher alignment summaries.
  • Optional simple baselines for quick performance sanity checks.

Installation

From source with uv

BenchAudit uses a standard pyproject.toml. The quickest source setup is with uv:

# 1) Create a virtual environment
uv venv
source .venv/bin/activate  # or .venv\Scripts\activate on Windows

# 2) Install dependencies declared in pyproject.toml
uv sync

If you need optional sequence alignment support, install EMBOSS so stretcher is available (e.g., sudo apt install emboss on Debian/Ubuntu).

Usage

The main entry point is run.py, which consumes one or more YAML configs and writes results under runs/ by default. After uv sync, you can call it via uv run python run.py ... or the installed console scripts:

  • uv run benchaudit ... (primary)
  • uv run bench ... (legacy alias)
# Analyze all configs in a folder
uv run python run.py --configs configs --out-root runs
# or: uv run benchaudit --configs configs --out-root runs

# Analyze a single config and train baselines
uv run python run.py --config configs/example.yml --benchmark
# or: uv run benchaudit --config configs/example.yml --benchmark

Outputs per config:

  • summary.json: split sizes, hygiene counts, similarity/conflict statistics, and runtime metadata.
  • records.csv: per-row view with cleaned SMILES, labels, and split tags.
  • conflicts.jsonl: detailed conflict rows.
  • cliffs.jsonl: detailed activity cliff rows.
  • sequence_alignments.jsonl: (DTI only) top alignments between splits.
  • performance.json: (when --benchmark) baseline model metrics and predictions.

New runs include a runtime block in summary.json with UTC start/end timestamps, total elapsed seconds/minutes, and stage-level timings. For existing artifacts that pre-date this metadata, generate a best-effort runtime table with:

python experiments/report_runtimes.py \
  --runs-root runs \
  --out-dir experiments/plots

The report prefers recorded runtimes when available, otherwise uses clearly labeled timestamp-based estimates or artifact-write lower bounds.

Generalized noise-injection experiments

To run synthetic noise-injection experiments across non-multitask datasets and multiple model classes without modifying the original Polaris-only experiment, see experiments/noise_generalization_experiment.md. The generalized driver writes results.csv, summary_by_fraction.csv, dataset_manifest.csv, errors.csv, and metadata.json under runs/degradation/noise_generalization.

Counterfactual benchmark-composition analysis

The utils.rank_fragility package implements a post-hoc leaderboard robustness analysis for molecular property prediction. It starts from an existing train/valid/test dataset and trained-model prediction CSVs on the original test set, then asks whether rankings and SOTA-vs-baseline margins remain stable when the audited chemical composition of the evaluation panel is changed.

Run it with:

python experiments/run_rank_fragility.py \
  --data data/dataset.csv \
  --pred_dir predictions/ \
  --id_col molecule_id \
  --smiles_col smiles \
  --label_col y \
  --split_col split \
  --task classification \
  --metric auroc \
  --baseline_model ecfp_rf \
  --sota_model auto \
  --near_leak_thresholds 0.85 0.90 \
  --primary_near_leak_threshold 0.85 \
  --regression_conflict_threshold 1.0 \
  --n_panels 1000 \
  --panel_size auto \
  --target_rates 0 0.05 0.10 0.25 observed 0.50 0.75 \
  --random_seed 13 \
  --out-dir runs/rank_fragility/

To run across existing BenchAudit artifacts in this repository, use batch mode. It discovers runs/*/*/records.csv, skips multitask datasets with --skip-multitask, skips DTI pair datasets by default, creates prediction files, and writes one output directory per dataset:

python experiments/run_rank_fragility.py \
  --from-runs-root runs \
  --batch-out-dir runs/rank_fragility \
  --skip-multitask \
  --train-splits train,valid \
  --batch-models ecfp_linear,ecfp_rf,lgbm_basic,lgbm_advanced,torch_mlp_basic,torch_mlp_advanced \
  --baseline_model ecfp_rf \
  --sota_model auto \
  --n_panels 1000 \
  --panel_size auto \
  --target_rates 0 0.05 0.10 0.25 observed 0.50 0.75 \
  --n-jobs 64 \
  --lgbm-device-type cpu \
  --mlp-accelerator gpu \
  --mlp-devices 1

Batch model names are ecfp_linear, ecfp_rf, lgbm_basic, lgbm_advanced, torch_mlp_basic, and torch_mlp_advanced. The aliases lgbm, torch_mlp, and mlp map to the basic versions. The Torch MLP uses the same Lightning-style training path as the generalized noise-injection study; --mlp-hidden-size, --mlp-max-epochs, --mlp-lr, --mlp-weight-decay, and --mlp-batch-size control the basic MLP, while --mlp-advanced-hidden-sizes, --mlp-advanced-max-epochs, --mlp-advanced-lr, --mlp-advanced-weight-decay, and --mlp-advanced-dropout control the advanced MLP. LightGBM uses --lgbm-estimators and --lgbm-learning-rate for the basic model and --lgbm-advanced-* options for the advanced model.

Default rank-fragility outputs are compact CSV summaries intended for manuscript analysis and version-control safety: audit summaries, original and clean leaderboards, rank probabilities, SOTA-vs-baseline margins by composition, Kendall rank correlations by composition, fragility summaries, and aggregate advantage decompositions. Per-panel manifests, per-panel scores/ranks, per-molecule annotations, reports, plots, and copied input CSVs are not written by default. Use scripts/prune_rank_fragility_outputs.py to remove legacy verbose generated artifacts from an existing runs/rank_fragility tree.

Dataset CSVs must contain molecule_id, smiles, y, and split, where split is one of train, valid, or test. Prediction files are one CSV per model in --pred_dir, with molecule_id, y_true, and y_pred; the file stem is used as the model name. For binary classification, y_pred is the predicted probability for class 1. For regression, it is the predicted continuous value.

Audit groups are mutually exclusive for test rows:

  • label_conflict: the same canonical molecule has conflicting labels.
  • exact_leak: the exact canonical test molecule appears in train.
  • near_train_analogue: the test molecule has high ECFP/Tanimoto similarity to train at the primary threshold.
  • same_scaffold: the test molecule shares a Murcko scaffold with train but is not assigned to a higher-priority group.
  • audit_clean: none of the above audit conditions applies.

Exact train-test duplicates and duplicate/conflicting labels are treated as true contamination. Near-train analogues are not treated as erroneous data; they represent analogue-rich local SAR interpolation and may be valid for lead optimization, but they are weaker evidence for generalization to novel chemical space. Same-scaffold overlap is kept as a separate stratum. Activity cliffs are not treated as contamination in this analysis.

The leakage_curve excludes label conflicts and controls the fraction of examples that are exact train-test leaks or near-train analogues. The conflict_curve controls the fraction of label-conflicting examples while excluding exact leaks where possible. The clean_reference mode samples only audit-clean molecules, and observed_composition resamples panels with the original audit-group proportions. Random matched controls use the same panel sizes and target-rate schedule as the leakage/conflict curves but randomize the composition.

Rank probabilities are empirical probabilities over generated panels, for example the probability that a model is rank 1 under a specified composition. SOTA margins are SOTA-vs-baseline metric differences with the sign normalized so positive always means the SOTA model is better, including lower-is-better metrics such as RMSE or log loss.

Interpretation examples:

  • If the SOTA rank probability remains high on clean-reference panels, the SOTA ranking is stable under audit-clean evaluation.
  • If the SOTA rank probability drops below 0.5 on clean-reference or zero-leakage panels, the original SOTA conclusion is rank-fragile under audit-clean evaluation.
  • If the SOTA-vs-baseline confidence interval overlaps zero, the SOTA margin is statistically indistinguishable from the baseline under that composition.
  • If performance increases with analogue-rich fraction, that is consistent with local SAR interpolation or leakage-like shortcut effects, not by itself proof that a model is intrinsically invalid.

Limitations: this is a post-hoc leaderboard robustness analysis. It does not replace full retraining on a newly curated benchmark. Clean panels can be smaller than the original test set. Near-train analogues are not necessarily erroneous; they represent analogue-rich interpolation. Results should be interpreted as stability of the benchmark conclusion, not proof that any architecture is intrinsically invalid.

Project layout

  • run.py: CLI runner that loads configs, builds loaders/analyzers, and writes artifacts.
  • utils/: loaders, analyzers, baseline helpers, and logging utilities.
  • utils/rank_fragility/: post-hoc counterfactual benchmark-composition analysis.
  • experiments/run_rank_fragility.py: repo-style entry point for the rank-fragility analysis.
  • configs/: example YAML configurations for supported datasets.
  • data/, runs/: expected data and output locations (not tracked).

Development

  • Tests: run python -m unittest discover -s tests -p "test_*.py" (or pytest tests if pytest is installed).
  • Test data: tiny dummy benchmark datasets live under tests/data/.
  • Docs: build with sphinx-build -W --keep-going -b html docs/source docs/_build/html (docs/source/reference/api_objects.rst provides autosummary-based API inventory).
  • Optional extras: Polaris datasets require polaris-lib; sequence alignment requires EMBOSS stretcher.

References

Metadata

Release files for benchaudit 2.1

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for benchaudit 2.1
File Size Uploaded
benchaudit-2.1.tar.gz 135.5 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for benchaudit 2.1
File Interpreter ABI Platform
benchaudit-2.1-py3-none-any.whl Python 3 none any Details

Total release size: 249.0 kB

Release files / benchaudit-2.1.tar.gz

Download URL benchaudit-2.1.tar.gz
Size 135.5 kB
Tags Source
SHA-256 checksum
How to use checksums
d7b5ffe08f75202f5685f696fea004675e0434c3d939356cdd33c6ddaf045f0c
BLAKE2b-256 checksum
How to use checksums
177ac8eab641cda4b92d14bab2e009ee13a67b527c67e25d98b972a87d67ceed
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/6.1.0 CPython/3.13.12

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Jun 26, 2026.

Transparency log

Release files / benchaudit-2.1-py3-none-any.whl

Download URL benchaudit-2.1-py3-none-any.whl
Size 113.5 kB
Tags Python 3
SHA-256 checksum
How to use checksums
312a07cee4bf5ec42944968dc48b0fe8d179d434b5f11f37e51cfb509918df1b
BLAKE2b-256 checksum
How to use checksums
72e7a439c5393c0f098bd56ab37f112e7d802511a2ba42b19a86320fc57900cf
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/6.1.0 CPython/3.13.12

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Jun 26, 2026.

Transparency log

Release history Release notifications | RSS feed

This release

2.1 This release

2 release files

0.1.1

2 release files

0.1.0

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page