MaldiAMRKit 0.20.0__tar.gz → 0.22.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.
- {maldiamrkit-0.20.0 → maldiamrkit-0.22.0/MaldiAMRKit.egg-info}/PKG-INFO +2 -2
- {maldiamrkit-0.20.0/MaldiAMRKit.egg-info → maldiamrkit-0.22.0}/PKG-INFO +2 -2
- {maldiamrkit-0.20.0 → maldiamrkit-0.22.0}/README.md +1 -1
- {maldiamrkit-0.20.0 → maldiamrkit-0.22.0}/maldiamrkit/__init__.py +1 -1
- {maldiamrkit-0.20.0 → maldiamrkit-0.22.0}/maldiamrkit/alignment/peak_align.py +14 -9
- {maldiamrkit-0.20.0 → maldiamrkit-0.22.0}/maldiamrkit/alignment/raw_warping.py +174 -29
- maldiamrkit-0.22.0/maldiamrkit/alignment/strategies.py +988 -0
- maldiamrkit-0.22.0/maldiamrkit/alignment/warping.py +628 -0
- {maldiamrkit-0.20.0 → maldiamrkit-0.22.0}/maldiamrkit/data/dataset_layouts.py +74 -3
- {maldiamrkit-0.20.0 → maldiamrkit-0.22.0}/maldiamrkit/data/input_layouts.py +70 -5
- {maldiamrkit-0.20.0 → maldiamrkit-0.22.0}/maldiamrkit/data/site_info.py +13 -0
- {maldiamrkit-0.20.0 → maldiamrkit-0.22.0}/maldiamrkit/detection/peaklist.py +17 -0
- {maldiamrkit-0.20.0 → maldiamrkit-0.22.0}/maldiamrkit/drift/monitor.py +57 -9
- {maldiamrkit-0.20.0 → maldiamrkit-0.22.0}/maldiamrkit/evaluation/splitting.py +24 -2
- {maldiamrkit-0.20.0 → maldiamrkit-0.22.0}/maldiamrkit/similarity/metrics.py +139 -23
- maldiamrkit-0.22.0/maldiamrkit/similarity/pairwise.py +230 -0
- {maldiamrkit-0.20.0 → maldiamrkit-0.22.0}/maldiamrkit/susceptibility/mic_encoder.py +28 -2
- maldiamrkit-0.20.0/maldiamrkit/alignment/strategies.py +0 -700
- maldiamrkit-0.20.0/maldiamrkit/alignment/warping.py +0 -370
- maldiamrkit-0.20.0/maldiamrkit/similarity/pairwise.py +0 -159
- {maldiamrkit-0.20.0 → maldiamrkit-0.22.0}/LICENSE +0 -0
- {maldiamrkit-0.20.0 → maldiamrkit-0.22.0}/MaldiAMRKit.egg-info/SOURCES.txt +0 -0
- {maldiamrkit-0.20.0 → maldiamrkit-0.22.0}/MaldiAMRKit.egg-info/dependency_links.txt +0 -0
- {maldiamrkit-0.20.0 → maldiamrkit-0.22.0}/MaldiAMRKit.egg-info/entry_points.txt +0 -0
- {maldiamrkit-0.20.0 → maldiamrkit-0.22.0}/MaldiAMRKit.egg-info/requires.txt +0 -0
- {maldiamrkit-0.20.0 → maldiamrkit-0.22.0}/MaldiAMRKit.egg-info/top_level.txt +0 -0
- {maldiamrkit-0.20.0 → maldiamrkit-0.22.0}/maldiamrkit/_compat.py +0 -0
- {maldiamrkit-0.20.0 → maldiamrkit-0.22.0}/maldiamrkit/_registry.py +0 -0
- {maldiamrkit-0.20.0 → maldiamrkit-0.22.0}/maldiamrkit/alignment/__init__.py +0 -0
- {maldiamrkit-0.20.0 → maldiamrkit-0.22.0}/maldiamrkit/cli.py +0 -0
- {maldiamrkit-0.20.0 → maldiamrkit-0.22.0}/maldiamrkit/data/__init__.py +0 -0
- {maldiamrkit-0.20.0 → maldiamrkit-0.22.0}/maldiamrkit/data/breakpoints/eucast/README.md +0 -0
- {maldiamrkit-0.20.0 → maldiamrkit-0.22.0}/maldiamrkit/data/breakpoints/eucast/eucast_v1.0.yaml +0 -0
- {maldiamrkit-0.20.0 → maldiamrkit-0.22.0}/maldiamrkit/data/breakpoints/eucast/eucast_v1.1.yaml +0 -0
- {maldiamrkit-0.20.0 → maldiamrkit-0.22.0}/maldiamrkit/data/breakpoints/eucast/eucast_v1.2.yaml +0 -0
- {maldiamrkit-0.20.0 → maldiamrkit-0.22.0}/maldiamrkit/data/breakpoints/eucast/eucast_v1.3.yaml +0 -0
- {maldiamrkit-0.20.0 → maldiamrkit-0.22.0}/maldiamrkit/data/breakpoints/eucast/eucast_v10.0.yaml +0 -0
- {maldiamrkit-0.20.0 → maldiamrkit-0.22.0}/maldiamrkit/data/breakpoints/eucast/eucast_v11.0.yaml +0 -0
- {maldiamrkit-0.20.0 → maldiamrkit-0.22.0}/maldiamrkit/data/breakpoints/eucast/eucast_v12.0.yaml +0 -0
- {maldiamrkit-0.20.0 → maldiamrkit-0.22.0}/maldiamrkit/data/breakpoints/eucast/eucast_v13.1.yaml +0 -0
- {maldiamrkit-0.20.0 → maldiamrkit-0.22.0}/maldiamrkit/data/breakpoints/eucast/eucast_v14.0.yaml +0 -0
- {maldiamrkit-0.20.0 → maldiamrkit-0.22.0}/maldiamrkit/data/breakpoints/eucast/eucast_v15.0.yaml +0 -0
- {maldiamrkit-0.20.0 → maldiamrkit-0.22.0}/maldiamrkit/data/breakpoints/eucast/eucast_v16.0.yaml +0 -0
- {maldiamrkit-0.20.0 → maldiamrkit-0.22.0}/maldiamrkit/data/breakpoints/eucast/eucast_v2.0.yaml +0 -0
- {maldiamrkit-0.20.0 → maldiamrkit-0.22.0}/maldiamrkit/data/breakpoints/eucast/eucast_v4.0.yaml +0 -0
- {maldiamrkit-0.20.0 → maldiamrkit-0.22.0}/maldiamrkit/data/breakpoints/eucast/eucast_v5.0.yaml +0 -0
- {maldiamrkit-0.20.0 → maldiamrkit-0.22.0}/maldiamrkit/data/breakpoints/eucast/eucast_v6.0.yaml +0 -0
- {maldiamrkit-0.20.0 → maldiamrkit-0.22.0}/maldiamrkit/data/breakpoints/eucast/eucast_v7.1.yaml +0 -0
- {maldiamrkit-0.20.0 → maldiamrkit-0.22.0}/maldiamrkit/data/breakpoints/eucast/eucast_v8.0.yaml +0 -0
- {maldiamrkit-0.20.0 → maldiamrkit-0.22.0}/maldiamrkit/data/breakpoints/eucast/eucast_v8.1.yaml +0 -0
- {maldiamrkit-0.20.0 → maldiamrkit-0.22.0}/maldiamrkit/data/breakpoints/eucast/eucast_v9.0.yaml +0 -0
- {maldiamrkit-0.20.0 → maldiamrkit-0.22.0}/maldiamrkit/data/breakpoints/example.yaml +0 -0
- {maldiamrkit-0.20.0 → maldiamrkit-0.22.0}/maldiamrkit/data/builder.py +0 -0
- {maldiamrkit-0.20.0 → maldiamrkit-0.22.0}/maldiamrkit/data/duplicates.py +0 -0
- {maldiamrkit-0.20.0 → maldiamrkit-0.22.0}/maldiamrkit/data/loader.py +0 -0
- {maldiamrkit-0.20.0 → maldiamrkit-0.22.0}/maldiamrkit/dataset.py +0 -0
- {maldiamrkit-0.20.0 → maldiamrkit-0.22.0}/maldiamrkit/detection/__init__.py +0 -0
- {maldiamrkit-0.20.0 → maldiamrkit-0.22.0}/maldiamrkit/detection/peak_detector.py +0 -0
- {maldiamrkit-0.20.0 → maldiamrkit-0.22.0}/maldiamrkit/differential/__init__.py +0 -0
- {maldiamrkit-0.20.0 → maldiamrkit-0.22.0}/maldiamrkit/differential/analysis.py +0 -0
- {maldiamrkit-0.20.0 → maldiamrkit-0.22.0}/maldiamrkit/differential/plots.py +0 -0
- {maldiamrkit-0.20.0 → maldiamrkit-0.22.0}/maldiamrkit/differential/stats.py +0 -0
- {maldiamrkit-0.20.0 → maldiamrkit-0.22.0}/maldiamrkit/drift/__init__.py +0 -0
- {maldiamrkit-0.20.0 → maldiamrkit-0.22.0}/maldiamrkit/drift/pca_drift.py +0 -0
- {maldiamrkit-0.20.0 → maldiamrkit-0.22.0}/maldiamrkit/drift/peak_drift.py +0 -0
- {maldiamrkit-0.20.0 → maldiamrkit-0.22.0}/maldiamrkit/drift/plots.py +0 -0
- {maldiamrkit-0.20.0 → maldiamrkit-0.22.0}/maldiamrkit/drift/reference.py +0 -0
- {maldiamrkit-0.20.0 → maldiamrkit-0.22.0}/maldiamrkit/evaluation/__init__.py +0 -0
- {maldiamrkit-0.20.0 → maldiamrkit-0.22.0}/maldiamrkit/evaluation/metrics.py +0 -0
- {maldiamrkit-0.20.0 → maldiamrkit-0.22.0}/maldiamrkit/evaluation/mic_regression.py +0 -0
- {maldiamrkit-0.20.0 → maldiamrkit-0.22.0}/maldiamrkit/filters.py +0 -0
- {maldiamrkit-0.20.0 → maldiamrkit-0.22.0}/maldiamrkit/io/__init__.py +0 -0
- {maldiamrkit-0.20.0 → maldiamrkit-0.22.0}/maldiamrkit/io/mic.py +0 -0
- {maldiamrkit-0.20.0 → maldiamrkit-0.22.0}/maldiamrkit/io/readers.py +0 -0
- {maldiamrkit-0.20.0 → maldiamrkit-0.22.0}/maldiamrkit/io/writers.py +0 -0
- {maldiamrkit-0.20.0 → maldiamrkit-0.22.0}/maldiamrkit/preprocessing/__init__.py +0 -0
- {maldiamrkit-0.20.0 → maldiamrkit-0.22.0}/maldiamrkit/preprocessing/binning.py +0 -0
- {maldiamrkit-0.20.0 → maldiamrkit-0.22.0}/maldiamrkit/preprocessing/merging.py +0 -0
- {maldiamrkit-0.20.0 → maldiamrkit-0.22.0}/maldiamrkit/preprocessing/pipeline.py +0 -0
- {maldiamrkit-0.20.0 → maldiamrkit-0.22.0}/maldiamrkit/preprocessing/preprocessing_pipeline.py +0 -0
- {maldiamrkit-0.20.0 → maldiamrkit-0.22.0}/maldiamrkit/preprocessing/quality.py +0 -0
- {maldiamrkit-0.20.0 → maldiamrkit-0.22.0}/maldiamrkit/preprocessing/transformers.py +0 -0
- {maldiamrkit-0.20.0 → maldiamrkit-0.22.0}/maldiamrkit/py.typed +0 -0
- {maldiamrkit-0.20.0 → maldiamrkit-0.22.0}/maldiamrkit/similarity/__init__.py +0 -0
- {maldiamrkit-0.20.0 → maldiamrkit-0.22.0}/maldiamrkit/similarity/clustering.py +0 -0
- {maldiamrkit-0.20.0 → maldiamrkit-0.22.0}/maldiamrkit/similarity/plots.py +0 -0
- {maldiamrkit-0.20.0 → maldiamrkit-0.22.0}/maldiamrkit/spectrum.py +0 -0
- {maldiamrkit-0.20.0 → maldiamrkit-0.22.0}/maldiamrkit/susceptibility/__init__.py +0 -0
- {maldiamrkit-0.20.0 → maldiamrkit-0.22.0}/maldiamrkit/susceptibility/breakpoint.py +0 -0
- {maldiamrkit-0.20.0 → maldiamrkit-0.22.0}/maldiamrkit/susceptibility/label_encoder.py +0 -0
- {maldiamrkit-0.20.0 → maldiamrkit-0.22.0}/maldiamrkit/visualization/__init__.py +0 -0
- {maldiamrkit-0.20.0 → maldiamrkit-0.22.0}/maldiamrkit/visualization/_common.py +0 -0
- {maldiamrkit-0.20.0 → maldiamrkit-0.22.0}/maldiamrkit/visualization/alignment_plots.py +0 -0
- {maldiamrkit-0.20.0 → maldiamrkit-0.22.0}/maldiamrkit/visualization/exploratory_plots.py +0 -0
- {maldiamrkit-0.20.0 → maldiamrkit-0.22.0}/maldiamrkit/visualization/peak_plots.py +0 -0
- {maldiamrkit-0.20.0 → maldiamrkit-0.22.0}/maldiamrkit/visualization/spectrum_plots.py +0 -0
- {maldiamrkit-0.20.0 → maldiamrkit-0.22.0}/pyproject.toml +0 -0
- {maldiamrkit-0.20.0 → maldiamrkit-0.22.0}/requirements-batch.txt +0 -0
- {maldiamrkit-0.20.0 → maldiamrkit-0.22.0}/requirements-dev.txt +0 -0
- {maldiamrkit-0.20.0 → maldiamrkit-0.22.0}/requirements-docs.txt +0 -0
- {maldiamrkit-0.20.0 → maldiamrkit-0.22.0}/requirements-formats.txt +0 -0
- {maldiamrkit-0.20.0 → maldiamrkit-0.22.0}/requirements.txt +0 -0
- {maldiamrkit-0.20.0 → maldiamrkit-0.22.0}/setup.cfg +0 -0
- {maldiamrkit-0.20.0 → maldiamrkit-0.22.0}/tests/test_compat.py +0 -0
- {maldiamrkit-0.20.0 → maldiamrkit-0.22.0}/tests/test_numerical_edge_cases.py +0 -0
- {maldiamrkit-0.20.0 → maldiamrkit-0.22.0}/tests/test_peak_detector.py +0 -0
- {maldiamrkit-0.20.0 → maldiamrkit-0.22.0}/tests/test_peaklist.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: MaldiAMRKit
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.22.0
|
|
4
4
|
Summary: A comprehensive toolkit for MALDI-TOF mass spectrometry data preprocessing for antimicrobial resistance (AMR) prediction purposes
|
|
5
5
|
Author-email: Ettore Rocchi <ettore.rocchi3@unibo.it>
|
|
6
6
|
License-Expression: MIT
|
|
@@ -140,7 +140,7 @@ pip install -e .[dev]
|
|
|
140
140
|
- **Replicate Merging**: Mean/median/weighted merging with correlation-based outlier detection
|
|
141
141
|
|
|
142
142
|
### Alignment & Detection
|
|
143
|
-
- **Spectral Alignment**: Shift, linear, piecewise, DTW, quadratic, cubic, and LOWESS warping for both binned and raw full-resolution spectra
|
|
143
|
+
- **Spectral Alignment**: Shift, linear, piecewise, DTW, quadratic, cubic, and LOWESS warping for both binned and raw full-resolution spectra. Spectra are first shifted and then aligned to the reference of the shifted spectra, a non-rigid warp is kept only when the matched peaks support it, and resampling preserves the total intensity; spectra of several species are best aligned one species at a time
|
|
144
144
|
- **Peak Detection**: Local maxima and persistent homology methods
|
|
145
145
|
- **Peak Sets**: `PeakSet` / `PeakList` represent each spectrum as a variable-length `(m/z, intensity)` set for peak-set models, via `MaldiPeakDetector.transform_peaklist()` on binned spectra or `create_peakset_input()` at full m/z resolution; extraction is stateless per spectrum, so results are cacheable without leakage
|
|
146
146
|
- **Fit-Free Peak Alignment**: `align_peaks()` warps a peak set onto caller-supplied reference peaks, so the reference stays fitted on the training split
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: MaldiAMRKit
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.22.0
|
|
4
4
|
Summary: A comprehensive toolkit for MALDI-TOF mass spectrometry data preprocessing for antimicrobial resistance (AMR) prediction purposes
|
|
5
5
|
Author-email: Ettore Rocchi <ettore.rocchi3@unibo.it>
|
|
6
6
|
License-Expression: MIT
|
|
@@ -140,7 +140,7 @@ pip install -e .[dev]
|
|
|
140
140
|
- **Replicate Merging**: Mean/median/weighted merging with correlation-based outlier detection
|
|
141
141
|
|
|
142
142
|
### Alignment & Detection
|
|
143
|
-
- **Spectral Alignment**: Shift, linear, piecewise, DTW, quadratic, cubic, and LOWESS warping for both binned and raw full-resolution spectra
|
|
143
|
+
- **Spectral Alignment**: Shift, linear, piecewise, DTW, quadratic, cubic, and LOWESS warping for both binned and raw full-resolution spectra. Spectra are first shifted and then aligned to the reference of the shifted spectra, a non-rigid warp is kept only when the matched peaks support it, and resampling preserves the total intensity; spectra of several species are best aligned one species at a time
|
|
144
144
|
- **Peak Detection**: Local maxima and persistent homology methods
|
|
145
145
|
- **Peak Sets**: `PeakSet` / `PeakList` represent each spectrum as a variable-length `(m/z, intensity)` set for peak-set models, via `MaldiPeakDetector.transform_peaklist()` on binned spectra or `create_peakset_input()` at full m/z resolution; extraction is stateless per spectrum, so results are cacheable without leakage
|
|
146
146
|
- **Fit-Free Peak Alignment**: `align_peaks()` warps a peak set onto caller-supplied reference peaks, so the reference stays fitted on the training split
|
|
@@ -79,7 +79,7 @@ pip install -e .[dev]
|
|
|
79
79
|
- **Replicate Merging**: Mean/median/weighted merging with correlation-based outlier detection
|
|
80
80
|
|
|
81
81
|
### Alignment & Detection
|
|
82
|
-
- **Spectral Alignment**: Shift, linear, piecewise, DTW, quadratic, cubic, and LOWESS warping for both binned and raw full-resolution spectra
|
|
82
|
+
- **Spectral Alignment**: Shift, linear, piecewise, DTW, quadratic, cubic, and LOWESS warping for both binned and raw full-resolution spectra. Spectra are first shifted and then aligned to the reference of the shifted spectra, a non-rigid warp is kept only when the matched peaks support it, and resampling preserves the total intensity; spectra of several species are best aligned one species at a time
|
|
83
83
|
- **Peak Detection**: Local maxima and persistent homology methods
|
|
84
84
|
- **Peak Sets**: `PeakSet` / `PeakList` represent each spectrum as a variable-length `(m/z, intensity)` set for peak-set models, via `MaldiPeakDetector.transform_peaklist()` on binned spectra or `create_peakset_input()` at full m/z resolution; extraction is stateless per spectrum, so results are cacheable without leakage
|
|
85
85
|
- **Fit-Free Peak Alignment**: `align_peaks()` warps a peak set onto caller-supplied reference peaks, so the reference stays fitted on the training split
|
|
@@ -25,18 +25,18 @@ def _build_strategy(
|
|
|
25
25
|
) -> AlignmentStrategy:
|
|
26
26
|
"""Instantiate the requested alignment strategy with its parameters."""
|
|
27
27
|
cls = _ALIGNMENT_REGISTRY[method]
|
|
28
|
+
# Peak sets carry no spectrum to correlate with: estimate from peaks only.
|
|
29
|
+
shared = dict(max_shift=max_shift_da, estimator="peaks", min_gain=None)
|
|
28
30
|
if method in (AlignmentMethod.shift, AlignmentMethod.linear):
|
|
29
|
-
return cls(
|
|
31
|
+
return cls(**shared)
|
|
30
32
|
if method == AlignmentMethod.piecewise:
|
|
31
|
-
return cls(
|
|
32
|
-
n_segments=n_segments, smooth_sigma=smooth_sigma, max_shift=max_shift_da
|
|
33
|
-
)
|
|
33
|
+
return cls(n_segments=n_segments, smooth_sigma=smooth_sigma, **shared)
|
|
34
34
|
if method == AlignmentMethod.quadratic:
|
|
35
|
-
return cls(
|
|
35
|
+
return cls(degree=2, **shared)
|
|
36
36
|
if method == AlignmentMethod.cubic:
|
|
37
|
-
return cls(
|
|
37
|
+
return cls(degree=3, **shared)
|
|
38
38
|
if method == AlignmentMethod.lowess:
|
|
39
|
-
return cls(
|
|
39
|
+
return cls(frac=lowess_frac, it=lowess_it, **shared)
|
|
40
40
|
return cls()
|
|
41
41
|
|
|
42
42
|
|
|
@@ -67,8 +67,9 @@ def align_peaks(
|
|
|
67
67
|
Warping strategy. ``"dtw"`` is unsupported for peak sets because it
|
|
68
68
|
resamples onto a dense grid and would destroy the set structure.
|
|
69
69
|
max_shift_da : float, default=50.0
|
|
70
|
-
|
|
71
|
-
|
|
70
|
+
Largest shift considered, in Daltons. Sample and reference peaks are
|
|
71
|
+
paired only when mutually nearest and within this distance (around
|
|
72
|
+
the global shift, for the non-rigid methods).
|
|
72
73
|
n_segments : int, default=5
|
|
73
74
|
Number of segments for ``method="piecewise"``.
|
|
74
75
|
smooth_sigma : float, default=2.0
|
|
@@ -96,6 +97,10 @@ def align_peaks(
|
|
|
96
97
|
from the median spacing of the input points; on a sparse peak set that
|
|
97
98
|
spacing is large, so the smoothing is effectively inactive and the warp
|
|
98
99
|
reduces to an unsmoothed piecewise-linear transform.
|
|
100
|
+
|
|
101
|
+
The global shift is the median offset of the mutually nearest peak
|
|
102
|
+
pairs. A non-rigid warp whose mapping is not strictly increasing is
|
|
103
|
+
replaced by that global shift, with a warning.
|
|
99
104
|
"""
|
|
100
105
|
method = AlignmentMethod(method)
|
|
101
106
|
if method == AlignmentMethod.dtw:
|
|
@@ -16,7 +16,15 @@ from ..io.readers import read_spectrum
|
|
|
16
16
|
from ..preprocessing.binning import BinningMethod, bin_spectrum
|
|
17
17
|
from ..preprocessing.pipeline import preprocess
|
|
18
18
|
from ..preprocessing.preprocessing_pipeline import PreprocessingPipeline
|
|
19
|
-
from .strategies import
|
|
19
|
+
from .strategies import (
|
|
20
|
+
_ALIGNMENT_REGISTRY,
|
|
21
|
+
_SHIFT_ESTIMATORS,
|
|
22
|
+
AlignmentMethod,
|
|
23
|
+
DTWStrategy,
|
|
24
|
+
ShiftStrategy,
|
|
25
|
+
_most_prominent,
|
|
26
|
+
)
|
|
27
|
+
from .warping import _renormalize
|
|
20
28
|
|
|
21
29
|
|
|
22
30
|
def create_raw_input(
|
|
@@ -76,7 +84,7 @@ def create_raw_input(
|
|
|
76
84
|
>>> # Use in pipeline
|
|
77
85
|
>>> from sklearn.pipeline import Pipeline
|
|
78
86
|
>>> pipe = Pipeline([
|
|
79
|
-
... ("warp", RawWarping(method="
|
|
87
|
+
... ("warp", RawWarping(method="lowess")),
|
|
80
88
|
... ("scaler", StandardScaler()),
|
|
81
89
|
... ])
|
|
82
90
|
>>> X_binned = pipe.fit_transform(X_raw)
|
|
@@ -117,7 +125,7 @@ class RawWarping(BaseEstimator, TransformerMixin):
|
|
|
117
125
|
----------
|
|
118
126
|
method : str, default="shift"
|
|
119
127
|
Warping method:
|
|
120
|
-
- "shift" : global m/z shift in Daltons
|
|
128
|
+
- "shift" : global m/z shift in Daltons, see ``shift_estimator``
|
|
121
129
|
- "linear" : linear m/z transformation (mz' = a*mz + b)
|
|
122
130
|
- "piecewise" : segment-wise m/z shifts with smoothing
|
|
123
131
|
- "dtw" : dynamic time warping
|
|
@@ -130,12 +138,17 @@ class RawWarping(BaseEstimator, TransformerMixin):
|
|
|
130
138
|
Binning method. One of 'uniform', 'proportional', 'adaptive', 'custom'.
|
|
131
139
|
bin_kwargs : dict, optional
|
|
132
140
|
Additional keyword arguments for binning.
|
|
133
|
-
max_shift_da : float, default=
|
|
134
|
-
|
|
141
|
+
max_shift_da : float, default=10.0
|
|
142
|
+
Largest shift considered, in Daltons. It bounds the global shift
|
|
143
|
+
(the total of both steps with ``prealign``) and the distance between
|
|
144
|
+
matched peak pairs.
|
|
135
145
|
n_segments : int, default=5
|
|
136
146
|
Number of segments for piecewise warping.
|
|
137
147
|
dtw_radius : int, default=10
|
|
138
|
-
Radius constraint for DTW.
|
|
148
|
+
Radius constraint for DTW. DTW memory grows with the square of the
|
|
149
|
+
number of reference points (about 10 GB per spectrum for a 0.5 Da
|
|
150
|
+
grid over 2-20 kDa), so a coarser ``interp_step`` is needed to run
|
|
151
|
+
it on full-resolution spectra.
|
|
139
152
|
smooth_sigma : float, default=2.0
|
|
140
153
|
Gaussian smoothing for piecewise transitions.
|
|
141
154
|
lowess_frac : float, default=0.3
|
|
@@ -159,6 +172,38 @@ class RawWarping(BaseEstimator, TransformerMixin):
|
|
|
159
172
|
n_jobs : int, default=1
|
|
160
173
|
Number of parallel jobs for transform. Use -1 for all available
|
|
161
174
|
cores, 1 for sequential processing.
|
|
175
|
+
shift_estimator : {"xcorr", "peaks"}, default="xcorr"
|
|
176
|
+
How the global shift is estimated. ``"xcorr"`` resamples the
|
|
177
|
+
spectrum onto a uniform grid at the reference spacing and takes the
|
|
178
|
+
lag (within ``max_shift_da``) that maximises the Pearson correlation
|
|
179
|
+
with the reference. ``"peaks"`` takes the median offset between
|
|
180
|
+
mutually nearest sample and reference peaks within ``max_shift_da``.
|
|
181
|
+
Either shift is applied only if it raises the correlation with the
|
|
182
|
+
reference by ``min_gain``.
|
|
183
|
+
min_gain : float, default=0.05
|
|
184
|
+
Minimum relative gain in correlation with the reference (as a
|
|
185
|
+
fraction of the correlation it improves on) required to apply a
|
|
186
|
+
shift and to keep the "dtw" result instead of the unwarped spectrum.
|
|
187
|
+
With ``prealign``, each step is checked against its own reference.
|
|
188
|
+
min_support : float, default=0.6
|
|
189
|
+
Share of the matched peak pairs that a non-rigid warp must bring
|
|
190
|
+
within ``max_shift_da / 3`` Daltons of their reference partner to be
|
|
191
|
+
used instead of the global shift.
|
|
192
|
+
n_peaks : int or None, default=200
|
|
193
|
+
Number of most prominent detected peaks, in each spectrum and in
|
|
194
|
+
the reference, used to match peaks (by the "peaks" shift estimator
|
|
195
|
+
and the non-rigid methods). ``None`` uses every detected peak.
|
|
196
|
+
prealign : bool, default=True
|
|
197
|
+
Shift the m/z axis of each spectrum first and fit the alignment to
|
|
198
|
+
the median of the shifted training spectra; :meth:`transform`
|
|
199
|
+
applies the same two steps at full resolution before binning, and
|
|
200
|
+
the global shift of both steps together stays within
|
|
201
|
+
``max_shift_da``. This keeps a median reference sharp when the
|
|
202
|
+
spectra come from different calibrations (for instance several
|
|
203
|
+
instruments).
|
|
204
|
+
renormalize : bool, default=False
|
|
205
|
+
Divide each aligned, binned spectrum by its total intensity, so
|
|
206
|
+
that it sums to 1 (spectra with no intensity are left unchanged).
|
|
162
207
|
|
|
163
208
|
Attributes
|
|
164
209
|
----------
|
|
@@ -167,7 +212,12 @@ class RawWarping(BaseEstimator, TransformerMixin):
|
|
|
167
212
|
ref_intensity_ : np.ndarray
|
|
168
213
|
Reference spectrum intensities (after fit).
|
|
169
214
|
ref_peaks_mz_ : np.ndarray
|
|
170
|
-
|
|
215
|
+
m/z positions of the ``n_peaks`` most prominent peaks of the
|
|
216
|
+
reference spectrum.
|
|
217
|
+
prealign_mz_, prealign_intensity_, prealign_peaks_mz_ : np.ndarray or None
|
|
218
|
+
Reference of the global-shift step applied first (and its peaks),
|
|
219
|
+
with ``prealign=True``; otherwise None. ``ref_mz_`` and
|
|
220
|
+
``ref_intensity_`` then hold the reference of the shifted spectra.
|
|
171
221
|
output_columns_ : pd.Index
|
|
172
222
|
Column names for output DataFrame (m/z bin centers).
|
|
173
223
|
pipeline_ : PreprocessingPipeline
|
|
@@ -184,7 +234,7 @@ class RawWarping(BaseEstimator, TransformerMixin):
|
|
|
184
234
|
>>>
|
|
185
235
|
>>> # Use in sklearn pipeline
|
|
186
236
|
>>> pipe = Pipeline([
|
|
187
|
-
... ("warp", RawWarping(method="
|
|
237
|
+
... ("warp", RawWarping(method="lowess", bin_width=3)),
|
|
188
238
|
... ("scaler", StandardScaler()),
|
|
189
239
|
... ("clf", RandomForestClassifier())
|
|
190
240
|
... ])
|
|
@@ -197,6 +247,22 @@ class RawWarping(BaseEstimator, TransformerMixin):
|
|
|
197
247
|
- Column "path": paths to raw spectrum files
|
|
198
248
|
|
|
199
249
|
Use `create_raw_input()` to easily create this DataFrame from a directory.
|
|
250
|
+
|
|
251
|
+
The non-rigid methods fit their warp on the ``n_peaks`` most prominent
|
|
252
|
+
peaks, matched around the global shift (after the shift step of
|
|
253
|
+
``prealign``), and use it only if the warped m/z axis is strictly
|
|
254
|
+
increasing (otherwise the global shift is used, with a warning) and it
|
|
255
|
+
is supported by at least ``min_support`` of the matched pairs. Apart
|
|
256
|
+
from "dtw", every method moves the m/z values and leaves the
|
|
257
|
+
intensities unchanged, so binning preserves the total intensity within
|
|
258
|
+
the m/z range; "dtw" does not, because it averages the sample points
|
|
259
|
+
matched to each reference point. ``renormalize=True`` makes every
|
|
260
|
+
output spectrum sum to 1 whatever the method.
|
|
261
|
+
|
|
262
|
+
Only the reference spectrum is learned in :meth:`fit`; :meth:`transform`
|
|
263
|
+
aligns each spectrum on its own (replicates of one sample are averaged
|
|
264
|
+
after alignment), so its result does not depend on the other spectra
|
|
265
|
+
transformed with it.
|
|
200
266
|
"""
|
|
201
267
|
|
|
202
268
|
def __init__(
|
|
@@ -205,7 +271,7 @@ class RawWarping(BaseEstimator, TransformerMixin):
|
|
|
205
271
|
bin_width: float = 3,
|
|
206
272
|
bin_method: str | BinningMethod = BinningMethod.uniform,
|
|
207
273
|
bin_kwargs: dict | None = None,
|
|
208
|
-
max_shift_da: float =
|
|
274
|
+
max_shift_da: float = 10.0,
|
|
209
275
|
n_segments: int = 5,
|
|
210
276
|
dtw_radius: int = 10,
|
|
211
277
|
smooth_sigma: float = 2.0,
|
|
@@ -217,6 +283,12 @@ class RawWarping(BaseEstimator, TransformerMixin):
|
|
|
217
283
|
min_reference_peaks: int = 5,
|
|
218
284
|
interp_step: float = 0.5,
|
|
219
285
|
n_jobs: int = 1,
|
|
286
|
+
shift_estimator: str = "xcorr",
|
|
287
|
+
min_gain: float = 0.05,
|
|
288
|
+
min_support: float = 0.6,
|
|
289
|
+
n_peaks: int | None = 200,
|
|
290
|
+
prealign: bool = True,
|
|
291
|
+
renormalize: bool = False,
|
|
220
292
|
) -> None:
|
|
221
293
|
self.method = AlignmentMethod(method)
|
|
222
294
|
self.bin_width = bin_width
|
|
@@ -236,6 +308,12 @@ class RawWarping(BaseEstimator, TransformerMixin):
|
|
|
236
308
|
)
|
|
237
309
|
self.min_reference_peaks = min_reference_peaks
|
|
238
310
|
self.n_jobs = n_jobs
|
|
311
|
+
self.shift_estimator = shift_estimator
|
|
312
|
+
self.min_gain = min_gain
|
|
313
|
+
self.min_support = min_support
|
|
314
|
+
self.n_peaks = n_peaks
|
|
315
|
+
self.prealign = prealign
|
|
316
|
+
self.renormalize = renormalize
|
|
239
317
|
|
|
240
318
|
def _load_raw_spectrum(self, path: str) -> pd.DataFrame:
|
|
241
319
|
"""Load and preprocess a raw spectrum from file."""
|
|
@@ -249,13 +327,12 @@ class RawWarping(BaseEstimator, TransformerMixin):
|
|
|
249
327
|
return preprocess(raw, self.pipeline_)
|
|
250
328
|
|
|
251
329
|
def _detect_peaks_mz(self, mz: np.ndarray, intensity: np.ndarray) -> np.ndarray:
|
|
252
|
-
"""
|
|
330
|
+
"""m/z positions of the ``n_peaks`` most prominent detected peaks."""
|
|
253
331
|
# Create temporary single-row DataFrame for peak detection
|
|
254
332
|
spec_df = pd.DataFrame([intensity], columns=mz)
|
|
255
333
|
peaks_df = self.peak_detector.transform(spec_df)
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
return mz[peak_mask]
|
|
334
|
+
peaks = np.flatnonzero(peaks_df.iloc[0].to_numpy() != 0)
|
|
335
|
+
return mz[_most_prominent(intensity, peaks, self.n_peaks)]
|
|
259
336
|
|
|
260
337
|
def _compute_raw_reference(
|
|
261
338
|
self, paths: list[str]
|
|
@@ -363,6 +440,18 @@ class RawWarping(BaseEstimator, TransformerMixin):
|
|
|
363
440
|
"Use create_raw_input() to create the input DataFrame."
|
|
364
441
|
)
|
|
365
442
|
|
|
443
|
+
if self.shift_estimator not in _SHIFT_ESTIMATORS:
|
|
444
|
+
raise ValueError(
|
|
445
|
+
f"shift_estimator must be one of {_SHIFT_ESTIMATORS}, "
|
|
446
|
+
f"got {self.shift_estimator!r}"
|
|
447
|
+
)
|
|
448
|
+
if self.min_gain < 0:
|
|
449
|
+
raise ValueError(f"min_gain must be >= 0, got {self.min_gain}")
|
|
450
|
+
if not (0.0 <= self.min_support <= 1.0):
|
|
451
|
+
raise ValueError(f"min_support must be in [0, 1], got {self.min_support}")
|
|
452
|
+
if self.n_peaks is not None and self.n_peaks < 1:
|
|
453
|
+
raise ValueError(f"n_peaks must be >= 1 or None, got {self.n_peaks}")
|
|
454
|
+
|
|
366
455
|
# Store preprocessing config
|
|
367
456
|
self.pipeline_ = self.pipeline or PreprocessingPipeline.default()
|
|
368
457
|
|
|
@@ -373,6 +462,16 @@ class RawWarping(BaseEstimator, TransformerMixin):
|
|
|
373
462
|
self.ref_mz_, self.ref_intensity_, self.ref_peaks_mz_ = (
|
|
374
463
|
self._compute_raw_reference(paths)
|
|
375
464
|
)
|
|
465
|
+
self.prealign_mz_ = self.prealign_intensity_ = self.prealign_peaks_mz_ = None
|
|
466
|
+
if self._prealigns():
|
|
467
|
+
self.prealign_mz_ = self.ref_mz_
|
|
468
|
+
self.prealign_intensity_ = self.ref_intensity_
|
|
469
|
+
self.prealign_peaks_mz_ = self.ref_peaks_mz_
|
|
470
|
+
if self.reference == "median":
|
|
471
|
+
self.ref_intensity_ = self._shifted_median(paths)
|
|
472
|
+
self.ref_peaks_mz_ = self._detect_peaks_mz(
|
|
473
|
+
self.ref_mz_, self.ref_intensity_
|
|
474
|
+
)
|
|
376
475
|
|
|
377
476
|
# Validate reference quality
|
|
378
477
|
n_peaks = len(self.ref_peaks_mz_)
|
|
@@ -394,30 +493,64 @@ class RawWarping(BaseEstimator, TransformerMixin):
|
|
|
394
493
|
def _get_strategy(self):
|
|
395
494
|
"""Build strategy instance from current parameters."""
|
|
396
495
|
cls = _ALIGNMENT_REGISTRY[self.method]
|
|
496
|
+
shared = dict(
|
|
497
|
+
max_shift=self.max_shift_da,
|
|
498
|
+
estimator=self.shift_estimator,
|
|
499
|
+
min_gain=self.min_gain,
|
|
500
|
+
)
|
|
501
|
+
warp = dict(shared, min_support=self.min_support)
|
|
397
502
|
if self.method == "shift":
|
|
398
|
-
return cls(
|
|
503
|
+
return cls(**shared)
|
|
399
504
|
elif self.method == "linear":
|
|
400
|
-
return cls(
|
|
505
|
+
return cls(**warp)
|
|
401
506
|
elif self.method == "piecewise":
|
|
402
507
|
return cls(
|
|
403
|
-
n_segments=self.n_segments,
|
|
404
|
-
smooth_sigma=self.smooth_sigma,
|
|
405
|
-
max_shift=self.max_shift_da,
|
|
508
|
+
n_segments=self.n_segments, smooth_sigma=self.smooth_sigma, **warp
|
|
406
509
|
)
|
|
407
510
|
elif self.method == "dtw":
|
|
408
|
-
return cls(dtw_radius=self.dtw_radius)
|
|
511
|
+
return cls(dtw_radius=self.dtw_radius, min_gain=self.min_gain)
|
|
409
512
|
elif self.method == "quadratic":
|
|
410
|
-
return cls(
|
|
513
|
+
return cls(degree=2, **warp)
|
|
411
514
|
elif self.method == "cubic":
|
|
412
|
-
return cls(
|
|
515
|
+
return cls(degree=3, **warp)
|
|
413
516
|
elif self.method == "lowess":
|
|
414
|
-
return cls(
|
|
415
|
-
max_shift=self.max_shift_da,
|
|
416
|
-
frac=self.lowess_frac,
|
|
417
|
-
it=self.lowess_it,
|
|
418
|
-
)
|
|
517
|
+
return cls(frac=self.lowess_frac, it=self.lowess_it, **warp)
|
|
419
518
|
return cls()
|
|
420
519
|
|
|
520
|
+
def _prealigns(self) -> bool:
|
|
521
|
+
"""Whether a global-shift step runs before the alignment."""
|
|
522
|
+
return bool(self.prealign)
|
|
523
|
+
|
|
524
|
+
def _prealign_shift(
|
|
525
|
+
self,
|
|
526
|
+
mz: np.ndarray,
|
|
527
|
+
intensity: np.ndarray,
|
|
528
|
+
peaks_mz: np.ndarray | None = None,
|
|
529
|
+
) -> float:
|
|
530
|
+
"""Global shift (in Daltons) of a spectrum to the prealign reference."""
|
|
531
|
+
if peaks_mz is None and self.shift_estimator == "peaks":
|
|
532
|
+
peaks_mz = self._detect_peaks_mz(mz, intensity)
|
|
533
|
+
strategy = ShiftStrategy(self.max_shift_da, self.shift_estimator, self.min_gain)
|
|
534
|
+
return strategy.estimate_raw(
|
|
535
|
+
mz,
|
|
536
|
+
intensity,
|
|
537
|
+
peaks_mz,
|
|
538
|
+
self.prealign_peaks_mz_,
|
|
539
|
+
self.prealign_mz_,
|
|
540
|
+
self.prealign_intensity_,
|
|
541
|
+
)
|
|
542
|
+
|
|
543
|
+
def _shifted_median(self, paths: list[str]) -> np.ndarray:
|
|
544
|
+
"""Median on ``ref_mz_`` of the training spectra after their shift."""
|
|
545
|
+
rows = np.empty((len(paths), len(self.ref_mz_)))
|
|
546
|
+
for i, path in enumerate(paths):
|
|
547
|
+
spec_df = self._load_raw_spectrum(path)
|
|
548
|
+
mz = spec_df["mass"].to_numpy()
|
|
549
|
+
intensity = spec_df["intensity"].to_numpy()
|
|
550
|
+
shift = self._prealign_shift(mz, intensity)
|
|
551
|
+
rows[i] = np.interp(self.ref_mz_, mz + shift, intensity)
|
|
552
|
+
return np.median(rows, axis=0)
|
|
553
|
+
|
|
421
554
|
def _bin_warped(self, mz: np.ndarray, intensity: np.ndarray) -> pd.DataFrame:
|
|
422
555
|
"""Bin warped raw spectrum to output grid."""
|
|
423
556
|
warped_df = pd.DataFrame({"mass": mz, "intensity": intensity})
|
|
@@ -440,8 +573,18 @@ class RawWarping(BaseEstimator, TransformerMixin):
|
|
|
440
573
|
intensity = spec_df["intensity"].to_numpy()
|
|
441
574
|
|
|
442
575
|
peaks_mz = self._detect_peaks_mz(mz, intensity)
|
|
576
|
+
applied = 0.0
|
|
577
|
+
if self.prealign_mz_ is not None:
|
|
578
|
+
applied = self._prealign_shift(mz, intensity, peaks_mz)
|
|
579
|
+
mz, peaks_mz = mz + applied, peaks_mz + applied
|
|
443
580
|
|
|
444
581
|
strategy = self._get_strategy()
|
|
582
|
+
budget = {}
|
|
583
|
+
if not isinstance(strategy, DTWStrategy):
|
|
584
|
+
budget["shift_bounds"] = (
|
|
585
|
+
-self.max_shift_da - applied,
|
|
586
|
+
self.max_shift_da - applied,
|
|
587
|
+
)
|
|
445
588
|
warped_mz, warped_int = strategy.align_raw(
|
|
446
589
|
mz,
|
|
447
590
|
intensity,
|
|
@@ -449,6 +592,7 @@ class RawWarping(BaseEstimator, TransformerMixin):
|
|
|
449
592
|
self.ref_peaks_mz_,
|
|
450
593
|
self.ref_mz_,
|
|
451
594
|
self.ref_intensity_,
|
|
595
|
+
**budget,
|
|
452
596
|
)
|
|
453
597
|
|
|
454
598
|
binned = self._bin_warped(warped_mz, warped_int)
|
|
@@ -495,9 +639,10 @@ class RawWarping(BaseEstimator, TransformerMixin):
|
|
|
495
639
|
)
|
|
496
640
|
|
|
497
641
|
# Combine into DataFrame
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
642
|
+
aligned = np.vstack(aligned_rows)
|
|
643
|
+
if self.renormalize:
|
|
644
|
+
_renormalize(aligned)
|
|
645
|
+
result = pd.DataFrame(aligned, index=X.index, columns=self.output_columns_)
|
|
501
646
|
|
|
502
647
|
# Average replicates when create_raw_input used strategy="average"
|
|
503
648
|
if "_original_id" in X.columns:
|