MaldiBatchKit 0.1.0__tar.gz → 0.2.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (49) hide show
  1. {maldibatchkit-0.1.0 → maldibatchkit-0.2.0/MaldiBatchKit.egg-info}/PKG-INFO +98 -74
  2. {maldibatchkit-0.1.0 → maldibatchkit-0.2.0}/MaldiBatchKit.egg-info/SOURCES.txt +5 -0
  3. {maldibatchkit-0.1.0 → maldibatchkit-0.2.0}/MaldiBatchKit.egg-info/requires.txt +1 -1
  4. {maldibatchkit-0.1.0/MaldiBatchKit.egg-info → maldibatchkit-0.2.0}/PKG-INFO +98 -74
  5. {maldibatchkit-0.1.0 → maldibatchkit-0.2.0}/README.md +96 -72
  6. {maldibatchkit-0.1.0 → maldibatchkit-0.2.0}/maldibatchkit/__init__.py +36 -4
  7. {maldibatchkit-0.1.0 → maldibatchkit-0.2.0}/maldibatchkit/corrections/__init__.py +5 -0
  8. maldibatchkit-0.2.0/maldibatchkit/corrections/auto.py +334 -0
  9. maldibatchkit-0.2.0/maldibatchkit/corrections/noop.py +59 -0
  10. {maldibatchkit-0.1.0 → maldibatchkit-0.2.0}/maldibatchkit/diagnostics/__init__.py +2 -0
  11. maldibatchkit-0.2.0/maldibatchkit/diagnostics/benchmark.py +745 -0
  12. maldibatchkit-0.2.0/maldibatchkit/metrics.py +579 -0
  13. {maldibatchkit-0.1.0 → maldibatchkit-0.2.0}/requirements.txt +1 -1
  14. maldibatchkit-0.2.0/tests/test_metrics.py +327 -0
  15. {maldibatchkit-0.1.0 → maldibatchkit-0.2.0}/tests/test_mz_axis_resolution.py +6 -10
  16. {maldibatchkit-0.1.0 → maldibatchkit-0.2.0}/tests/test_package.py +1 -1
  17. {maldibatchkit-0.1.0 → maldibatchkit-0.2.0}/LICENSE +0 -0
  18. {maldibatchkit-0.1.0 → maldibatchkit-0.2.0}/MaldiBatchKit.egg-info/dependency_links.txt +0 -0
  19. {maldibatchkit-0.1.0 → maldibatchkit-0.2.0}/MaldiBatchKit.egg-info/entry_points.txt +0 -0
  20. {maldibatchkit-0.1.0 → maldibatchkit-0.2.0}/MaldiBatchKit.egg-info/top_level.txt +0 -0
  21. {maldibatchkit-0.1.0 → maldibatchkit-0.2.0}/maldibatchkit/_base.py +0 -0
  22. {maldibatchkit-0.1.0 → maldibatchkit-0.2.0}/maldibatchkit/_cli_io.py +0 -0
  23. {maldibatchkit-0.1.0 → maldibatchkit-0.2.0}/maldibatchkit/_utils.py +0 -0
  24. {maldibatchkit-0.1.0 → maldibatchkit-0.2.0}/maldibatchkit/cli.py +0 -0
  25. {maldibatchkit-0.1.0 → maldibatchkit-0.2.0}/maldibatchkit/corrections/baselines.py +0 -0
  26. {maldibatchkit-0.1.0 → maldibatchkit-0.2.0}/maldibatchkit/corrections/combat.py +0 -0
  27. {maldibatchkit-0.1.0 → maldibatchkit-0.2.0}/maldibatchkit/corrections/harmony.py +0 -0
  28. {maldibatchkit-0.1.0 → maldibatchkit-0.2.0}/maldibatchkit/corrections/limma.py +0 -0
  29. {maldibatchkit-0.1.0 → maldibatchkit-0.2.0}/maldibatchkit/corrections/maldi.py +0 -0
  30. {maldibatchkit-0.1.0 → maldibatchkit-0.2.0}/maldibatchkit/corrections/quality_weighted.py +0 -0
  31. {maldibatchkit-0.1.0 → maldibatchkit-0.2.0}/maldibatchkit/diagnostics/generic.py +0 -0
  32. {maldibatchkit-0.1.0 → maldibatchkit-0.2.0}/maldibatchkit/diagnostics/maldi.py +0 -0
  33. {maldibatchkit-0.1.0 → maldibatchkit-0.2.0}/maldibatchkit/diagnostics/report.py +0 -0
  34. {maldibatchkit-0.1.0 → maldibatchkit-0.2.0}/maldibatchkit/integrations/__init__.py +0 -0
  35. {maldibatchkit-0.1.0 → maldibatchkit-0.2.0}/maldibatchkit/integrations/maldiset.py +0 -0
  36. {maldibatchkit-0.1.0 → maldibatchkit-0.2.0}/maldibatchkit/py.typed +0 -0
  37. {maldibatchkit-0.1.0 → maldibatchkit-0.2.0}/maldibatchkit/viz/__init__.py +0 -0
  38. {maldibatchkit-0.1.0 → maldibatchkit-0.2.0}/maldibatchkit/viz/peaks.py +0 -0
  39. {maldibatchkit-0.1.0 → maldibatchkit-0.2.0}/maldibatchkit/viz/summary.py +0 -0
  40. {maldibatchkit-0.1.0 → maldibatchkit-0.2.0}/maldibatchkit/viz/umap.py +0 -0
  41. {maldibatchkit-0.1.0 → maldibatchkit-0.2.0}/pyproject.toml +0 -0
  42. {maldibatchkit-0.1.0 → maldibatchkit-0.2.0}/requirements-dev.txt +0 -0
  43. {maldibatchkit-0.1.0 → maldibatchkit-0.2.0}/requirements-docs.txt +0 -0
  44. {maldibatchkit-0.1.0 → maldibatchkit-0.2.0}/requirements-viz.txt +0 -0
  45. {maldibatchkit-0.1.0 → maldibatchkit-0.2.0}/setup.cfg +0 -0
  46. {maldibatchkit-0.1.0 → maldibatchkit-0.2.0}/tests/test_cli.py +0 -0
  47. {maldibatchkit-0.1.0 → maldibatchkit-0.2.0}/tests/test_cli_io.py +0 -0
  48. {maldibatchkit-0.1.0 → maldibatchkit-0.2.0}/tests/test_no_data_leakage.py +0 -0
  49. {maldibatchkit-0.1.0 → maldibatchkit-0.2.0}/tests/test_utils.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: MaldiBatchKit
3
- Version: 0.1.0
3
+ Version: 0.2.0
4
4
  Summary: Batch-effect correction methods for MALDI-TOF spectra in clinical AMR prediction workflows
5
5
  Author-email: Ettore Rocchi <ettore.rocchi3@unibo.it>
6
6
  License-Expression: MIT
@@ -29,7 +29,7 @@ Requires-Dist: scikit-learn>=1.6.0
29
29
  Requires-Dist: matplotlib>=3.4.0
30
30
  Requires-Dist: combatlearn>=2.0.0
31
31
  Requires-Dist: harmonypy<2,>=0.2.0
32
- Requires-Dist: maldiamrkit>=0.12.0
32
+ Requires-Dist: maldiamrkit>=0.15.0
33
33
  Requires-Dist: typer>=0.9.0
34
34
  Provides-Extra: dev
35
35
  Requires-Dist: pytest>=7.0.0; extra == "dev"
@@ -55,8 +55,10 @@ Dynamic: license-file
55
55
 
56
56
  [![CI](https://github.com/EttoreRocchi/MaldiBatchKit/actions/workflows/ci.yml/badge.svg)](https://github.com/EttoreRocchi/MaldiBatchKit/actions/workflows/ci.yml)
57
57
  [![Coverage](https://codecov.io/github/EttoreRocchi/MaldiBatchKit/branch/main/graph/badge.svg)](https://codecov.io/github/EttoreRocchi/MaldiBatchKit)
58
- [![Docs](https://readthedocs.org/projects/maldibatchkit/badge/?version=latest)](https://maldibatchkit.readthedocs.io/en/latest/)
59
- [![Python](https://img.shields.io/badge/python-3.10--3.13-blue)](https://pypi.org/project/maldibatchkit/)
58
+ [![Documentation](https://img.shields.io/badge/docs-online-blue)](https://maldibatchkit.readthedocs.io/)
59
+
60
+ [![PyPI Version](https://img.shields.io/pypi/v/maldibatchkit)](https://pypi.org/project/maldibatchkit/)
61
+ [![Python](https://img.shields.io/pypi/pyversions/maldibatchkit)](https://pypi.org/project/maldibatchkit/)
60
62
  [![License](https://img.shields.io/github/license/EttoreRocchi/MaldiBatchKit)](https://github.com/EttoreRocchi/MaldiBatchKit/blob/main/LICENSE)
61
63
 
62
64
  <p align="center">
@@ -73,15 +75,11 @@ Dynamic: license-file
73
75
  <a href="#quick-start">Quick Start</a> •
74
76
  <a href="#algorithms">Algorithms</a> •
75
77
  <a href="#diagnostics">Diagnostics</a> •
78
+ <a href="#maldisuite-ecosystem">MaldiSuite</a> •
76
79
  <a href="#citation">Citation</a>
77
80
  </p>
78
81
 
79
- MaldiBatchKit is part of the **MaldiSuite** ecosystem and complements
80
- [MaldiAMRKit](https://github.com/EttoreRocchi/MaldiAMRKit): where
81
- MaldiAMRKit handles preprocessing, alignment and AMR-aware evaluation,
82
- MaldiBatchKit focuses on the *harmonization* step, removing the
83
- inter-batch / inter-site shifts that plague multi-centre MALDI-TOF
84
- studies.
82
+ MaldiBatchKit is part of the **MaldiSuite** ecosystem and complements [MaldiAMRKit](https://github.com/EttoreRocchi/MaldiAMRKit): where MaldiAMRKit handles preprocessing, alignment and AMR-aware evaluation, MaldiBatchKit focuses on the *harmonization* step, removing the inter-batch / inter-site shifts that plague multi-centre MALDI-TOF studies.
85
83
 
86
84
  ## Installation
87
85
 
@@ -97,40 +95,34 @@ pip install maldibatchkit[dev] # testing + linting
97
95
  pip install maldibatchkit[docs] # sphinx
98
96
  ```
99
97
 
100
- `maldiamrkit` is a core dependency - installing MaldiBatchKit pulls
101
- it in automatically. `BatchAwareWarping` reuses
102
- `maldiamrkit.alignment.Warping` under the hood, and the
103
- `MaldiSetAdapter` bridges to `maldiamrkit.MaldiSet` for end-to-end
104
- AMR workflows.
98
+ `maldiamrkit` is a core dependency - installing MaldiBatchKit pulls it in automatically. `BatchAwareWarping` reuses `maldiamrkit.alignment.Warping` under the hood, and the `MaldiSetAdapter` bridges to `maldiamrkit.MaldiSet` for end-to-end AMR workflows.
99
+
100
+ ### Install the full MaldiSuite
101
+
102
+ To install MaldiBatchKit together with [MaldiAMRKit](https://github.com/EttoreRocchi/MaldiAMRKit) and [MaldiDeepKit](https://github.com/EttoreRocchi/MaldiDeepKit) at compatible versions, install the [`maldisuite`](https://pypi.org/project/maldisuite/) meta-package:
103
+
104
+ ```bash
105
+ pip install maldisuite
106
+ ```
107
+
108
+ Visit the **MaldiSuite** landing page at <https://ettorerocchi.github.io/MaldiSuite/>.
105
109
 
106
110
  ## Features
107
111
 
108
- - **Unified sklearn API** (`BaseEstimator` + `TransformerMixin`) for
109
- every correction method. `batch` and covariates are passed at
110
- construction time and aligned to `X.index` at `fit` / `transform`,
111
- so the same object works inside `Pipeline` / cross-validation
112
- without data leakage.
113
- - **ComBat variants** (Johnson 2007, Fortin 2018, Chen 2022 CovBat)
114
- re-exported from [combatlearn](https://github.com/EttoreRocchi/combatlearn).
112
+ - **Unified sklearn API** (`BaseEstimator` + `TransformerMixin`) for every correction method. `batch` and covariates are passed at construction time and aligned to `X.index` at `fit` / `transform`, so the same object works inside `Pipeline` / cross-validation without data leakage.
113
+ - **ComBat variants** (Johnson 2007, Fortin 2018, Chen 2022 CovBat) re-exported from [combatlearn](https://github.com/EttoreRocchi/combatlearn).
115
114
  - **Limma `removeBatchEffect`** (Ritchie et al. 2015).
116
115
  - **Harmony** (Korsunsky et al. 2019) via [harmonypy](https://github.com/slowkow/harmonypy), with a **mandatory, frozen PCA preprocessing stage** so it behaves sensibly on high-dimensional MALDI-TOF intensity matrices (tune with the `n_components=` argument).
117
- - **Simple baselines**: median centering, z-score per batch,
118
- reference scaling.
116
+ - **Simple baselines**: median centering, z-score per batch, reference scaling.
119
117
  - **MALDI-specific corrections**:
120
- - `BatchAwareWarping` - per-batch m/z warping sharing a global
121
- reference (wraps `maldiamrkit.alignment.Warping`).
122
- - `QualityWeightedComBat` - weighted empirical-Bayes ComBat
123
- variant where low-SNR spectra contribute less to the shrinkage
124
- prior.
125
- - `SpeciesAwareComBat` - convenience preset for ComBat-Fortin with
126
- `species` as the protected biological covariate.
127
- - **Diagnostics**: kBET, LISI, silhouette-by-batch, per-batch peak
128
- drift, per-batch TIC coefficient of variation, per-batch spectrum
129
- count, plus a combined `diagnostic_report` DataFrame summary.
130
- - **Visualization**: UMAP before/after, per-batch peak-shape overlays,
131
- before/after bar charts.
132
- - **Integration adapter**: `MaldiSetAdapter` turns a
133
- `maldiamrkit.MaldiSet` into a corrected `MaldiSet` in one call.
118
+ - `BatchAwareWarping` - per-batch m/z warping sharing a global reference (wraps `maldiamrkit.alignment.Warping`).
119
+ - `QualityWeightedComBat` - weighted empirical-Bayes ComBat variant where low-SNR spectra contribute less to the shrinkage prior.
120
+ - `SpeciesAwareComBat` - convenience preset for ComBat-Fortin with `species` as the protected biological covariate.
121
+ - **Diagnostics**: kBET, LISI, silhouette-by-batch, per-batch peak drift, per-batch TIC coefficient of variation, per-batch spectrum count, plus a combined `diagnostic_report` DataFrame summary.
122
+ - **Method selection**: `AutoCorrector` exposes `method` as a settable hyperparameter so `GridSearchCV` can sweep across corrector families and let the downstream classifier metric (AUROC) decide. Ships with a `NoOpCorrector` so "do nothing" can sit on the candidate list as an honest baseline.
123
+ - **Diagnostic benchmark**: `BatchCorrectionBenchmark` runs a fixed set of metrics across multiple correctors with stratified bootstrap CIs and a tidy `(method, metric, value, ci_lo, ci_hi)` summary, ready for paper-figure comparisons.
124
+ - **Visualization**: UMAP before/after, per-batch peak-shape overlays, before/after bar charts.
125
+ - **Integration adapter**: `MaldiSetAdapter` turns a `maldiamrkit.MaldiSet` into a corrected `MaldiSet` in one call.
134
126
  - **CLI**: `maldibatchkit correct ...` and `maldibatchkit diagnose ...`.
135
127
 
136
128
  ## Quick start
@@ -160,8 +152,7 @@ X_train_c = corrector.transform(X_train)
160
152
  X_test_c = corrector.transform(X_test) # same parameters applied to test
161
153
  ```
162
154
 
163
- `batch` is indexed by the same sample IDs that X uses, so the
164
- corrector picks the right subset on each call.
155
+ `batch` is indexed by the same sample IDs that X uses, so the corrector picks the right subset on each call.
165
156
 
166
157
  ### MaldiSet integration
167
158
 
@@ -183,9 +174,7 @@ corrected_ds.y # AMR labels, unchanged
183
174
 
184
175
  ### CLI
185
176
 
186
- The CLI is organised as `maldibatchkit correct <method>` +
187
- `maldibatchkit diagnose`. Every method has its own subcommand with
188
- only the flags it actually uses:
177
+ The CLI is organised as `maldibatchkit correct <method>` + `maldibatchkit diagnose`. Every method has its own subcommand with only the flags it actually uses:
189
178
 
190
179
  ```bash
191
180
  # Vanilla Johnson ComBat
@@ -214,8 +203,7 @@ maldibatchkit diagnose \
214
203
  --batch-csv batch.csv --mz-csv mz.csv -o report.csv
215
204
  ```
216
205
 
217
- NPZ inputs bundle X, index, columns, and batch labels in one file, so
218
- the same commands work without sidecar CSVs:
206
+ NPZ inputs bundle X, index, columns, and batch labels in one file, so the same commands work without sidecar CSVs:
219
207
 
220
208
  ```bash
221
209
  maldibatchkit correct combat-fortin \
@@ -224,11 +212,7 @@ maldibatchkit correct combat-fortin \
224
212
  -o corrected.npz
225
213
  ```
226
214
 
227
- Run `maldibatchkit correct <method> --help` for the full flag list of
228
- any corrector. `combat-fortin` / `combat-chen` refuse to run without
229
- covariates (they would silently reduce to Johnson ComBat);
230
- `species-combat` / `quality-combat` require their dedicated
231
- `--species-csv` / `--quality-csv` inputs.
215
+ Run `maldibatchkit correct <method> --help` for the full flag list of any corrector. `combat-fortin` / `combat-chen` refuse to run without covariates (they would silently reduce to Johnson ComBat); `species-combat` / `quality-combat` require their dedicated `--species-csv` / `--quality-csv` inputs.
232
216
 
233
217
  ## Algorithms
234
218
 
@@ -243,27 +227,65 @@ covariates (they would silently reduce to Johnson ComBat);
243
227
  | Batch-aware warping | `BatchAwareWarping` | no | yes |
244
228
  | Quality-weighted ComBat | `QualityWeightedComBat` | no | yes |
245
229
  | Species-aware ComBat | `SpeciesAwareComBat` | species | yes |
230
+ | Identity / no-op | `NoOpCorrector` | n/a | yes |
231
+ | Meta-corrector | `AutoCorrector` | inherits inner | yes |
246
232
 
247
- See the `QualityWeightedComBat` docstring for the mathematical
248
- formulation of the weighted empirical-Bayes update.
233
+ See the `QualityWeightedComBat` docstring for the mathematical formulation of the weighted empirical-Bayes update.
234
+
235
+ ### Choosing a corrector
236
+
237
+ Picking among the methods above usually means asking one of two
238
+ questions: *"which corrector gives the best AMR classifier?"* or
239
+ *"which corrector mixes batches best while keeping species apart?"*.
240
+ MaldiBatchKit ships one tool for each:
241
+
242
+ ```python
243
+ from sklearn.linear_model import LogisticRegression
244
+ from sklearn.model_selection import GridSearchCV
245
+ from sklearn.pipeline import Pipeline
246
+ from maldibatchkit import AutoCorrector
247
+
248
+ pipe = Pipeline([
249
+ ("correct", AutoCorrector(batch=batch, discrete_covariates=species)),
250
+ ("clf", LogisticRegression(max_iter=1000)),
251
+ ])
252
+ grid = GridSearchCV(
253
+ pipe,
254
+ param_grid={"correct__method": ["noop", "combat-fortin", "harmony", "qw-combat"]},
255
+ scoring="roc_auc",
256
+ )
257
+ grid.fit(X, y)
258
+ ```
259
+
260
+ ```python
261
+ from maldibatchkit import ComBat, NoOpCorrector
262
+ from maldibatchkit.diagnostics import BatchCorrectionBenchmark
263
+
264
+ bench = BatchCorrectionBenchmark(
265
+ correctors={
266
+ "none": NoOpCorrector(batch=batch),
267
+ "fortin": ComBat(batch=batch, method="fortin", discrete_covariates=species),
268
+ },
269
+ metrics=("kbet", "lisi_normalized", "species_preservation"),
270
+ n_bootstrap=500,
271
+ random_state=0,
272
+ ).fit(X, batch=batch, species=species)
273
+ bench.rank(by="species_preservation")
274
+ ```
275
+
276
+ See [docs / Choosing a corrector](https://maldibatchkit.readthedocs.io/en/latest/choosing.html) for the full recipe.
249
277
 
250
278
  ## Extending MaldiBatchKit
251
279
 
252
- Every corrector in this package inherits from `BaseBatchCorrector`,
253
- which is re-exported at the top level. Subclass it, implement
254
- `_fit_impl` and `_transform_impl`, and you get a scikit-learn compatible,
255
- train/test-safe corrector for free - the base class handles index
256
- alignment between `X` and the stored `batch` labels, NaN / finite
257
- checks, DataFrame-vs-ndarray round-tripping, and the `feature_names_in_`
258
- / `n_features_in_` / `get_feature_names_out` sklearn bookkeeping.
280
+ Every corrector in this package inherits from `BaseBatchCorrector`, which is re-exported at the top level. Subclass it, implement `_fit_impl` and `_transform_impl`, and you get a scikit-learn compatible, train/test-safe corrector for free - the base class handles index alignment between `X` and the stored `batch` labels, NaN / finite checks, DataFrame-vs-ndarray round-tripping, and the `feature_names_in_` / `n_features_in_` / `get_feature_names_out` sklearn bookkeeping.
259
281
 
260
- Minimal custom corrector:
282
+ Minimal custom corrector (toy example - not shipped with the package):
261
283
 
262
284
  ```python
263
285
  import pandas as pd
264
286
  from maldibatchkit import BaseBatchCorrector
265
287
 
266
- class MeanCentering(BaseBatchCorrector):
288
+ class MyMeanCentering(BaseBatchCorrector):
267
289
  """Subtract per-batch means from each feature."""
268
290
 
269
291
  def _fit_impl(self, X_df, batch):
@@ -294,7 +316,7 @@ from sklearn.preprocessing import StandardScaler
294
316
  from sklearn.ensemble import RandomForestClassifier
295
317
 
296
318
  pipe = Pipeline([
297
- ("mean", MeanCentering(batch=batch)),
319
+ ("mean", MyMeanCentering(batch=batch)), # the class defined just above
298
320
  ("scaler", StandardScaler()),
299
321
  ("clf", RandomForestClassifier()),
300
322
  ])
@@ -307,14 +329,9 @@ Conventions (see `CONTRIBUTING.md`):
307
329
  - NumPy-style docstring on every public class.
308
330
  - Fitted attributes end in `_` (`self.batch_means_`, not `self.means`).
309
331
  - `transform` must be idempotent - no side effects outside `fit`.
310
- - Raise a clear `ImportError` (not a bare `ModuleNotFoundError`) when
311
- an optional dependency is missing; see `Harmony._require_harmonypy`
312
- for the reference pattern.
332
+ - Raise a clear `ImportError` (not a bare `ModuleNotFoundError`) when an optional dependency is missing; see `Harmony._require_harmonypy` for the reference pattern.
313
333
 
314
- Look at `maldibatchkit/corrections/baselines.py` for the simplest
315
- end-to-end references (`MedianCentering`, `ZScorePerBatch`,
316
- `ReferenceScaling`), or at `quality_weighted.py` for a corrector with
317
- an iterative fit.
334
+ Look at `maldibatchkit/corrections/baselines.py` for the simplest end-to-end references (`MedianCentering`, `ZScorePerBatch`, `ReferenceScaling`), or at `quality_weighted.py` for a corrector with an iterative fit.
318
335
 
319
336
  ## Diagnostics
320
337
 
@@ -326,9 +343,17 @@ from maldibatchkit.diagnostics import (
326
343
  )
327
344
  ```
328
345
 
329
- All metrics take the same `(X, batch)` signature. `diagnostic_report`
330
- composes them into a tidy DataFrame suitable for
331
- `plot_diagnostic_summary`.
346
+ All metrics take the same `(X, batch)` signature. `diagnostic_report` composes them into a tidy DataFrame suitable for `plot_diagnostic_summary`.
347
+
348
+ ## MaldiSuite Ecosystem
349
+
350
+ MaldiBatchKit is the harmonisation package of the **MaldiSuite** ecosystem:
351
+
352
+ - **[MaldiAMRKit](https://github.com/EttoreRocchi/MaldiAMRKit)** - data model (`MaldiSpectrum`, `MaldiSet`), preprocessing, alignment, peak detection, differential analysis, and AMR-aware evaluation.
353
+ - **MaldiBatchKit** (this package) - batch-effect correction and harmonisation for multi-centre / multi-instrument MALDI-TOF spectra.
354
+ - **[MaldiDeepKit](https://github.com/EttoreRocchi/MaldiDeepKit)** - sklearn-compatible deep learning classifiers (MLP, CNN, ResNet, Transformer).
355
+
356
+ The three packages share the `MaldiSet` / `MaldiSpectrum` data model and are designed to compose in a single end-to-end pipeline. Install the full suite with `pip install maldisuite`. Landing page: [MaldiSuite](<https://ettorerocchi.github.io/MaldiSuite/>).
332
357
 
333
358
  ## Citation
334
359
 
@@ -336,8 +361,7 @@ If you use MaldiBatchKit in academic work please cite:
336
361
 
337
362
  > _Citation will be available soon._
338
363
 
339
- along with the upstream references for whichever methods you apply
340
- (Johnson 2007, Fortin 2018, Chen 2022, Ritchie 2015, Korsunsky 2019).
364
+ along with the upstream references for whichever methods you apply (Johnson 2007, Fortin 2018, Chen 2022, Ritchie 2015, Korsunsky 2019).
341
365
 
342
366
  ## License
343
367
 
@@ -16,15 +16,19 @@ maldibatchkit/_base.py
16
16
  maldibatchkit/_cli_io.py
17
17
  maldibatchkit/_utils.py
18
18
  maldibatchkit/cli.py
19
+ maldibatchkit/metrics.py
19
20
  maldibatchkit/py.typed
20
21
  maldibatchkit/corrections/__init__.py
22
+ maldibatchkit/corrections/auto.py
21
23
  maldibatchkit/corrections/baselines.py
22
24
  maldibatchkit/corrections/combat.py
23
25
  maldibatchkit/corrections/harmony.py
24
26
  maldibatchkit/corrections/limma.py
25
27
  maldibatchkit/corrections/maldi.py
28
+ maldibatchkit/corrections/noop.py
26
29
  maldibatchkit/corrections/quality_weighted.py
27
30
  maldibatchkit/diagnostics/__init__.py
31
+ maldibatchkit/diagnostics/benchmark.py
28
32
  maldibatchkit/diagnostics/generic.py
29
33
  maldibatchkit/diagnostics/maldi.py
30
34
  maldibatchkit/diagnostics/report.py
@@ -36,6 +40,7 @@ maldibatchkit/viz/summary.py
36
40
  maldibatchkit/viz/umap.py
37
41
  tests/test_cli.py
38
42
  tests/test_cli_io.py
43
+ tests/test_metrics.py
39
44
  tests/test_mz_axis_resolution.py
40
45
  tests/test_no_data_leakage.py
41
46
  tests/test_package.py
@@ -5,7 +5,7 @@ scikit-learn>=1.6.0
5
5
  matplotlib>=3.4.0
6
6
  combatlearn>=2.0.0
7
7
  harmonypy<2,>=0.2.0
8
- maldiamrkit>=0.12.0
8
+ maldiamrkit>=0.15.0
9
9
  typer>=0.9.0
10
10
 
11
11
  [dev]
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: MaldiBatchKit
3
- Version: 0.1.0
3
+ Version: 0.2.0
4
4
  Summary: Batch-effect correction methods for MALDI-TOF spectra in clinical AMR prediction workflows
5
5
  Author-email: Ettore Rocchi <ettore.rocchi3@unibo.it>
6
6
  License-Expression: MIT
@@ -29,7 +29,7 @@ Requires-Dist: scikit-learn>=1.6.0
29
29
  Requires-Dist: matplotlib>=3.4.0
30
30
  Requires-Dist: combatlearn>=2.0.0
31
31
  Requires-Dist: harmonypy<2,>=0.2.0
32
- Requires-Dist: maldiamrkit>=0.12.0
32
+ Requires-Dist: maldiamrkit>=0.15.0
33
33
  Requires-Dist: typer>=0.9.0
34
34
  Provides-Extra: dev
35
35
  Requires-Dist: pytest>=7.0.0; extra == "dev"
@@ -55,8 +55,10 @@ Dynamic: license-file
55
55
 
56
56
  [![CI](https://github.com/EttoreRocchi/MaldiBatchKit/actions/workflows/ci.yml/badge.svg)](https://github.com/EttoreRocchi/MaldiBatchKit/actions/workflows/ci.yml)
57
57
  [![Coverage](https://codecov.io/github/EttoreRocchi/MaldiBatchKit/branch/main/graph/badge.svg)](https://codecov.io/github/EttoreRocchi/MaldiBatchKit)
58
- [![Docs](https://readthedocs.org/projects/maldibatchkit/badge/?version=latest)](https://maldibatchkit.readthedocs.io/en/latest/)
59
- [![Python](https://img.shields.io/badge/python-3.10--3.13-blue)](https://pypi.org/project/maldibatchkit/)
58
+ [![Documentation](https://img.shields.io/badge/docs-online-blue)](https://maldibatchkit.readthedocs.io/)
59
+
60
+ [![PyPI Version](https://img.shields.io/pypi/v/maldibatchkit)](https://pypi.org/project/maldibatchkit/)
61
+ [![Python](https://img.shields.io/pypi/pyversions/maldibatchkit)](https://pypi.org/project/maldibatchkit/)
60
62
  [![License](https://img.shields.io/github/license/EttoreRocchi/MaldiBatchKit)](https://github.com/EttoreRocchi/MaldiBatchKit/blob/main/LICENSE)
61
63
 
62
64
  <p align="center">
@@ -73,15 +75,11 @@ Dynamic: license-file
73
75
  <a href="#quick-start">Quick Start</a> •
74
76
  <a href="#algorithms">Algorithms</a> •
75
77
  <a href="#diagnostics">Diagnostics</a> •
78
+ <a href="#maldisuite-ecosystem">MaldiSuite</a> •
76
79
  <a href="#citation">Citation</a>
77
80
  </p>
78
81
 
79
- MaldiBatchKit is part of the **MaldiSuite** ecosystem and complements
80
- [MaldiAMRKit](https://github.com/EttoreRocchi/MaldiAMRKit): where
81
- MaldiAMRKit handles preprocessing, alignment and AMR-aware evaluation,
82
- MaldiBatchKit focuses on the *harmonization* step, removing the
83
- inter-batch / inter-site shifts that plague multi-centre MALDI-TOF
84
- studies.
82
+ MaldiBatchKit is part of the **MaldiSuite** ecosystem and complements [MaldiAMRKit](https://github.com/EttoreRocchi/MaldiAMRKit): where MaldiAMRKit handles preprocessing, alignment and AMR-aware evaluation, MaldiBatchKit focuses on the *harmonization* step, removing the inter-batch / inter-site shifts that plague multi-centre MALDI-TOF studies.
85
83
 
86
84
  ## Installation
87
85
 
@@ -97,40 +95,34 @@ pip install maldibatchkit[dev] # testing + linting
97
95
  pip install maldibatchkit[docs] # sphinx
98
96
  ```
99
97
 
100
- `maldiamrkit` is a core dependency - installing MaldiBatchKit pulls
101
- it in automatically. `BatchAwareWarping` reuses
102
- `maldiamrkit.alignment.Warping` under the hood, and the
103
- `MaldiSetAdapter` bridges to `maldiamrkit.MaldiSet` for end-to-end
104
- AMR workflows.
98
+ `maldiamrkit` is a core dependency - installing MaldiBatchKit pulls it in automatically. `BatchAwareWarping` reuses `maldiamrkit.alignment.Warping` under the hood, and the `MaldiSetAdapter` bridges to `maldiamrkit.MaldiSet` for end-to-end AMR workflows.
99
+
100
+ ### Install the full MaldiSuite
101
+
102
+ To install MaldiBatchKit together with [MaldiAMRKit](https://github.com/EttoreRocchi/MaldiAMRKit) and [MaldiDeepKit](https://github.com/EttoreRocchi/MaldiDeepKit) at compatible versions, install the [`maldisuite`](https://pypi.org/project/maldisuite/) meta-package:
103
+
104
+ ```bash
105
+ pip install maldisuite
106
+ ```
107
+
108
+ Visit the **MaldiSuite** landing page at <https://ettorerocchi.github.io/MaldiSuite/>.
105
109
 
106
110
  ## Features
107
111
 
108
- - **Unified sklearn API** (`BaseEstimator` + `TransformerMixin`) for
109
- every correction method. `batch` and covariates are passed at
110
- construction time and aligned to `X.index` at `fit` / `transform`,
111
- so the same object works inside `Pipeline` / cross-validation
112
- without data leakage.
113
- - **ComBat variants** (Johnson 2007, Fortin 2018, Chen 2022 CovBat)
114
- re-exported from [combatlearn](https://github.com/EttoreRocchi/combatlearn).
112
+ - **Unified sklearn API** (`BaseEstimator` + `TransformerMixin`) for every correction method. `batch` and covariates are passed at construction time and aligned to `X.index` at `fit` / `transform`, so the same object works inside `Pipeline` / cross-validation without data leakage.
113
+ - **ComBat variants** (Johnson 2007, Fortin 2018, Chen 2022 CovBat) re-exported from [combatlearn](https://github.com/EttoreRocchi/combatlearn).
115
114
  - **Limma `removeBatchEffect`** (Ritchie et al. 2015).
116
115
  - **Harmony** (Korsunsky et al. 2019) via [harmonypy](https://github.com/slowkow/harmonypy), with a **mandatory, frozen PCA preprocessing stage** so it behaves sensibly on high-dimensional MALDI-TOF intensity matrices (tune with the `n_components=` argument).
117
- - **Simple baselines**: median centering, z-score per batch,
118
- reference scaling.
116
+ - **Simple baselines**: median centering, z-score per batch, reference scaling.
119
117
  - **MALDI-specific corrections**:
120
- - `BatchAwareWarping` - per-batch m/z warping sharing a global
121
- reference (wraps `maldiamrkit.alignment.Warping`).
122
- - `QualityWeightedComBat` - weighted empirical-Bayes ComBat
123
- variant where low-SNR spectra contribute less to the shrinkage
124
- prior.
125
- - `SpeciesAwareComBat` - convenience preset for ComBat-Fortin with
126
- `species` as the protected biological covariate.
127
- - **Diagnostics**: kBET, LISI, silhouette-by-batch, per-batch peak
128
- drift, per-batch TIC coefficient of variation, per-batch spectrum
129
- count, plus a combined `diagnostic_report` DataFrame summary.
130
- - **Visualization**: UMAP before/after, per-batch peak-shape overlays,
131
- before/after bar charts.
132
- - **Integration adapter**: `MaldiSetAdapter` turns a
133
- `maldiamrkit.MaldiSet` into a corrected `MaldiSet` in one call.
118
+ - `BatchAwareWarping` - per-batch m/z warping sharing a global reference (wraps `maldiamrkit.alignment.Warping`).
119
+ - `QualityWeightedComBat` - weighted empirical-Bayes ComBat variant where low-SNR spectra contribute less to the shrinkage prior.
120
+ - `SpeciesAwareComBat` - convenience preset for ComBat-Fortin with `species` as the protected biological covariate.
121
+ - **Diagnostics**: kBET, LISI, silhouette-by-batch, per-batch peak drift, per-batch TIC coefficient of variation, per-batch spectrum count, plus a combined `diagnostic_report` DataFrame summary.
122
+ - **Method selection**: `AutoCorrector` exposes `method` as a settable hyperparameter so `GridSearchCV` can sweep across corrector families and let the downstream classifier metric (AUROC) decide. Ships with a `NoOpCorrector` so "do nothing" can sit on the candidate list as an honest baseline.
123
+ - **Diagnostic benchmark**: `BatchCorrectionBenchmark` runs a fixed set of metrics across multiple correctors with stratified bootstrap CIs and a tidy `(method, metric, value, ci_lo, ci_hi)` summary, ready for paper-figure comparisons.
124
+ - **Visualization**: UMAP before/after, per-batch peak-shape overlays, before/after bar charts.
125
+ - **Integration adapter**: `MaldiSetAdapter` turns a `maldiamrkit.MaldiSet` into a corrected `MaldiSet` in one call.
134
126
  - **CLI**: `maldibatchkit correct ...` and `maldibatchkit diagnose ...`.
135
127
 
136
128
  ## Quick start
@@ -160,8 +152,7 @@ X_train_c = corrector.transform(X_train)
160
152
  X_test_c = corrector.transform(X_test) # same parameters applied to test
161
153
  ```
162
154
 
163
- `batch` is indexed by the same sample IDs that X uses, so the
164
- corrector picks the right subset on each call.
155
+ `batch` is indexed by the same sample IDs that X uses, so the corrector picks the right subset on each call.
165
156
 
166
157
  ### MaldiSet integration
167
158
 
@@ -183,9 +174,7 @@ corrected_ds.y # AMR labels, unchanged
183
174
 
184
175
  ### CLI
185
176
 
186
- The CLI is organised as `maldibatchkit correct <method>` +
187
- `maldibatchkit diagnose`. Every method has its own subcommand with
188
- only the flags it actually uses:
177
+ The CLI is organised as `maldibatchkit correct <method>` + `maldibatchkit diagnose`. Every method has its own subcommand with only the flags it actually uses:
189
178
 
190
179
  ```bash
191
180
  # Vanilla Johnson ComBat
@@ -214,8 +203,7 @@ maldibatchkit diagnose \
214
203
  --batch-csv batch.csv --mz-csv mz.csv -o report.csv
215
204
  ```
216
205
 
217
- NPZ inputs bundle X, index, columns, and batch labels in one file, so
218
- the same commands work without sidecar CSVs:
206
+ NPZ inputs bundle X, index, columns, and batch labels in one file, so the same commands work without sidecar CSVs:
219
207
 
220
208
  ```bash
221
209
  maldibatchkit correct combat-fortin \
@@ -224,11 +212,7 @@ maldibatchkit correct combat-fortin \
224
212
  -o corrected.npz
225
213
  ```
226
214
 
227
- Run `maldibatchkit correct <method> --help` for the full flag list of
228
- any corrector. `combat-fortin` / `combat-chen` refuse to run without
229
- covariates (they would silently reduce to Johnson ComBat);
230
- `species-combat` / `quality-combat` require their dedicated
231
- `--species-csv` / `--quality-csv` inputs.
215
+ Run `maldibatchkit correct <method> --help` for the full flag list of any corrector. `combat-fortin` / `combat-chen` refuse to run without covariates (they would silently reduce to Johnson ComBat); `species-combat` / `quality-combat` require their dedicated `--species-csv` / `--quality-csv` inputs.
232
216
 
233
217
  ## Algorithms
234
218
 
@@ -243,27 +227,65 @@ covariates (they would silently reduce to Johnson ComBat);
243
227
  | Batch-aware warping | `BatchAwareWarping` | no | yes |
244
228
  | Quality-weighted ComBat | `QualityWeightedComBat` | no | yes |
245
229
  | Species-aware ComBat | `SpeciesAwareComBat` | species | yes |
230
+ | Identity / no-op | `NoOpCorrector` | n/a | yes |
231
+ | Meta-corrector | `AutoCorrector` | inherits inner | yes |
246
232
 
247
- See the `QualityWeightedComBat` docstring for the mathematical
248
- formulation of the weighted empirical-Bayes update.
233
+ See the `QualityWeightedComBat` docstring for the mathematical formulation of the weighted empirical-Bayes update.
234
+
235
+ ### Choosing a corrector
236
+
237
+ Picking among the methods above usually means asking one of two
238
+ questions: *"which corrector gives the best AMR classifier?"* or
239
+ *"which corrector mixes batches best while keeping species apart?"*.
240
+ MaldiBatchKit ships one tool for each:
241
+
242
+ ```python
243
+ from sklearn.linear_model import LogisticRegression
244
+ from sklearn.model_selection import GridSearchCV
245
+ from sklearn.pipeline import Pipeline
246
+ from maldibatchkit import AutoCorrector
247
+
248
+ pipe = Pipeline([
249
+ ("correct", AutoCorrector(batch=batch, discrete_covariates=species)),
250
+ ("clf", LogisticRegression(max_iter=1000)),
251
+ ])
252
+ grid = GridSearchCV(
253
+ pipe,
254
+ param_grid={"correct__method": ["noop", "combat-fortin", "harmony", "qw-combat"]},
255
+ scoring="roc_auc",
256
+ )
257
+ grid.fit(X, y)
258
+ ```
259
+
260
+ ```python
261
+ from maldibatchkit import ComBat, NoOpCorrector
262
+ from maldibatchkit.diagnostics import BatchCorrectionBenchmark
263
+
264
+ bench = BatchCorrectionBenchmark(
265
+ correctors={
266
+ "none": NoOpCorrector(batch=batch),
267
+ "fortin": ComBat(batch=batch, method="fortin", discrete_covariates=species),
268
+ },
269
+ metrics=("kbet", "lisi_normalized", "species_preservation"),
270
+ n_bootstrap=500,
271
+ random_state=0,
272
+ ).fit(X, batch=batch, species=species)
273
+ bench.rank(by="species_preservation")
274
+ ```
275
+
276
+ See [docs / Choosing a corrector](https://maldibatchkit.readthedocs.io/en/latest/choosing.html) for the full recipe.
249
277
 
250
278
  ## Extending MaldiBatchKit
251
279
 
252
- Every corrector in this package inherits from `BaseBatchCorrector`,
253
- which is re-exported at the top level. Subclass it, implement
254
- `_fit_impl` and `_transform_impl`, and you get a scikit-learn compatible,
255
- train/test-safe corrector for free - the base class handles index
256
- alignment between `X` and the stored `batch` labels, NaN / finite
257
- checks, DataFrame-vs-ndarray round-tripping, and the `feature_names_in_`
258
- / `n_features_in_` / `get_feature_names_out` sklearn bookkeeping.
280
+ Every corrector in this package inherits from `BaseBatchCorrector`, which is re-exported at the top level. Subclass it, implement `_fit_impl` and `_transform_impl`, and you get a scikit-learn compatible, train/test-safe corrector for free - the base class handles index alignment between `X` and the stored `batch` labels, NaN / finite checks, DataFrame-vs-ndarray round-tripping, and the `feature_names_in_` / `n_features_in_` / `get_feature_names_out` sklearn bookkeeping.
259
281
 
260
- Minimal custom corrector:
282
+ Minimal custom corrector (toy example - not shipped with the package):
261
283
 
262
284
  ```python
263
285
  import pandas as pd
264
286
  from maldibatchkit import BaseBatchCorrector
265
287
 
266
- class MeanCentering(BaseBatchCorrector):
288
+ class MyMeanCentering(BaseBatchCorrector):
267
289
  """Subtract per-batch means from each feature."""
268
290
 
269
291
  def _fit_impl(self, X_df, batch):
@@ -294,7 +316,7 @@ from sklearn.preprocessing import StandardScaler
294
316
  from sklearn.ensemble import RandomForestClassifier
295
317
 
296
318
  pipe = Pipeline([
297
- ("mean", MeanCentering(batch=batch)),
319
+ ("mean", MyMeanCentering(batch=batch)), # the class defined just above
298
320
  ("scaler", StandardScaler()),
299
321
  ("clf", RandomForestClassifier()),
300
322
  ])
@@ -307,14 +329,9 @@ Conventions (see `CONTRIBUTING.md`):
307
329
  - NumPy-style docstring on every public class.
308
330
  - Fitted attributes end in `_` (`self.batch_means_`, not `self.means`).
309
331
  - `transform` must be idempotent - no side effects outside `fit`.
310
- - Raise a clear `ImportError` (not a bare `ModuleNotFoundError`) when
311
- an optional dependency is missing; see `Harmony._require_harmonypy`
312
- for the reference pattern.
332
+ - Raise a clear `ImportError` (not a bare `ModuleNotFoundError`) when an optional dependency is missing; see `Harmony._require_harmonypy` for the reference pattern.
313
333
 
314
- Look at `maldibatchkit/corrections/baselines.py` for the simplest
315
- end-to-end references (`MedianCentering`, `ZScorePerBatch`,
316
- `ReferenceScaling`), or at `quality_weighted.py` for a corrector with
317
- an iterative fit.
334
+ Look at `maldibatchkit/corrections/baselines.py` for the simplest end-to-end references (`MedianCentering`, `ZScorePerBatch`, `ReferenceScaling`), or at `quality_weighted.py` for a corrector with an iterative fit.
318
335
 
319
336
  ## Diagnostics
320
337
 
@@ -326,9 +343,17 @@ from maldibatchkit.diagnostics import (
326
343
  )
327
344
  ```
328
345
 
329
- All metrics take the same `(X, batch)` signature. `diagnostic_report`
330
- composes them into a tidy DataFrame suitable for
331
- `plot_diagnostic_summary`.
346
+ All metrics take the same `(X, batch)` signature. `diagnostic_report` composes them into a tidy DataFrame suitable for `plot_diagnostic_summary`.
347
+
348
+ ## MaldiSuite Ecosystem
349
+
350
+ MaldiBatchKit is the harmonisation package of the **MaldiSuite** ecosystem:
351
+
352
+ - **[MaldiAMRKit](https://github.com/EttoreRocchi/MaldiAMRKit)** - data model (`MaldiSpectrum`, `MaldiSet`), preprocessing, alignment, peak detection, differential analysis, and AMR-aware evaluation.
353
+ - **MaldiBatchKit** (this package) - batch-effect correction and harmonisation for multi-centre / multi-instrument MALDI-TOF spectra.
354
+ - **[MaldiDeepKit](https://github.com/EttoreRocchi/MaldiDeepKit)** - sklearn-compatible deep learning classifiers (MLP, CNN, ResNet, Transformer).
355
+
356
+ The three packages share the `MaldiSet` / `MaldiSpectrum` data model and are designed to compose in a single end-to-end pipeline. Install the full suite with `pip install maldisuite`. Landing page: [MaldiSuite](<https://ettorerocchi.github.io/MaldiSuite/>).
332
357
 
333
358
  ## Citation
334
359
 
@@ -336,8 +361,7 @@ If you use MaldiBatchKit in academic work please cite:
336
361
 
337
362
  > _Citation will be available soon._
338
363
 
339
- along with the upstream references for whichever methods you apply
340
- (Johnson 2007, Fortin 2018, Chen 2022, Ritchie 2015, Korsunsky 2019).
364
+ along with the upstream references for whichever methods you apply (Johnson 2007, Fortin 2018, Chen 2022, Ritchie 2015, Korsunsky 2019).
341
365
 
342
366
  ## License
343
367