MaldiAMRKit 0.22.0__tar.gz → 0.22.1__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.22.0 → maldiamrkit-0.22.1/MaldiAMRKit.egg-info}/PKG-INFO +5 -4
- {maldiamrkit-0.22.0 → maldiamrkit-0.22.1}/MaldiAMRKit.egg-info/SOURCES.txt +3 -0
- {maldiamrkit-0.22.0 → maldiamrkit-0.22.1}/MaldiAMRKit.egg-info/requires.txt +1 -0
- {maldiamrkit-0.22.0/MaldiAMRKit.egg-info → maldiamrkit-0.22.1}/PKG-INFO +5 -4
- {maldiamrkit-0.22.0 → maldiamrkit-0.22.1}/README.md +3 -3
- {maldiamrkit-0.22.0 → maldiamrkit-0.22.1}/maldiamrkit/__init__.py +1 -1
- maldiamrkit-0.22.1/maldiamrkit/alignment/_dtw.py +82 -0
- maldiamrkit-0.22.1/maldiamrkit/alignment/_versioning.py +87 -0
- {maldiamrkit-0.22.0 → maldiamrkit-0.22.1}/maldiamrkit/alignment/peak_align.py +9 -4
- {maldiamrkit-0.22.0 → maldiamrkit-0.22.1}/maldiamrkit/alignment/raw_warping.py +117 -13
- {maldiamrkit-0.22.0 → maldiamrkit-0.22.1}/maldiamrkit/alignment/strategies.py +56 -23
- {maldiamrkit-0.22.0 → maldiamrkit-0.22.1}/maldiamrkit/alignment/warping.py +23 -3
- {maldiamrkit-0.22.0 → maldiamrkit-0.22.1}/maldiamrkit/cli.py +19 -1
- maldiamrkit-0.22.1/maldiamrkit/data/_metadata.py +33 -0
- {maldiamrkit-0.22.0 → maldiamrkit-0.22.1}/maldiamrkit/data/builder.py +1 -1
- {maldiamrkit-0.22.0 → maldiamrkit-0.22.1}/maldiamrkit/data/dataset_layouts.py +168 -53
- {maldiamrkit-0.22.0 → maldiamrkit-0.22.1}/maldiamrkit/data/duplicates.py +35 -21
- {maldiamrkit-0.22.0 → maldiamrkit-0.22.1}/maldiamrkit/data/input_layouts.py +6 -4
- maldiamrkit-0.22.1/maldiamrkit/data/loader.py +405 -0
- {maldiamrkit-0.22.0 → maldiamrkit-0.22.1}/maldiamrkit/dataset.py +164 -46
- {maldiamrkit-0.22.0 → maldiamrkit-0.22.1}/maldiamrkit/detection/peak_detector.py +21 -8
- {maldiamrkit-0.22.0 → maldiamrkit-0.22.1}/maldiamrkit/detection/peaklist.py +74 -18
- {maldiamrkit-0.22.0 → maldiamrkit-0.22.1}/maldiamrkit/differential/analysis.py +14 -0
- {maldiamrkit-0.22.0 → maldiamrkit-0.22.1}/maldiamrkit/drift/monitor.py +27 -5
- {maldiamrkit-0.22.0 → maldiamrkit-0.22.1}/maldiamrkit/drift/peak_drift.py +9 -2
- {maldiamrkit-0.22.0 → maldiamrkit-0.22.1}/maldiamrkit/evaluation/metrics.py +103 -29
- {maldiamrkit-0.22.0 → maldiamrkit-0.22.1}/maldiamrkit/evaluation/mic_regression.py +18 -7
- {maldiamrkit-0.22.0 → maldiamrkit-0.22.1}/maldiamrkit/evaluation/splitting.py +149 -25
- {maldiamrkit-0.22.0 → maldiamrkit-0.22.1}/maldiamrkit/filters.py +15 -8
- {maldiamrkit-0.22.0 → maldiamrkit-0.22.1}/maldiamrkit/io/readers.py +31 -4
- {maldiamrkit-0.22.0 → maldiamrkit-0.22.1}/maldiamrkit/preprocessing/binning.py +16 -9
- {maldiamrkit-0.22.0 → maldiamrkit-0.22.1}/maldiamrkit/preprocessing/merging.py +11 -8
- {maldiamrkit-0.22.0 → maldiamrkit-0.22.1}/maldiamrkit/preprocessing/quality.py +24 -20
- {maldiamrkit-0.22.0 → maldiamrkit-0.22.1}/maldiamrkit/preprocessing/transformers.py +7 -5
- {maldiamrkit-0.22.0 → maldiamrkit-0.22.1}/maldiamrkit/susceptibility/breakpoint.py +22 -6
- {maldiamrkit-0.22.0 → maldiamrkit-0.22.1}/maldiamrkit/susceptibility/label_encoder.py +15 -1
- {maldiamrkit-0.22.0 → maldiamrkit-0.22.1}/maldiamrkit/susceptibility/mic_encoder.py +21 -6
- {maldiamrkit-0.22.0 → maldiamrkit-0.22.1}/requirements.txt +3 -0
- {maldiamrkit-0.22.0 → maldiamrkit-0.22.1}/tests/test_peak_detector.py +44 -0
- {maldiamrkit-0.22.0 → maldiamrkit-0.22.1}/tests/test_peaklist.py +119 -0
- maldiamrkit-0.22.0/maldiamrkit/data/loader.py +0 -250
- {maldiamrkit-0.22.0 → maldiamrkit-0.22.1}/LICENSE +0 -0
- {maldiamrkit-0.22.0 → maldiamrkit-0.22.1}/MaldiAMRKit.egg-info/dependency_links.txt +0 -0
- {maldiamrkit-0.22.0 → maldiamrkit-0.22.1}/MaldiAMRKit.egg-info/entry_points.txt +0 -0
- {maldiamrkit-0.22.0 → maldiamrkit-0.22.1}/MaldiAMRKit.egg-info/top_level.txt +0 -0
- {maldiamrkit-0.22.0 → maldiamrkit-0.22.1}/maldiamrkit/_compat.py +0 -0
- {maldiamrkit-0.22.0 → maldiamrkit-0.22.1}/maldiamrkit/_registry.py +0 -0
- {maldiamrkit-0.22.0 → maldiamrkit-0.22.1}/maldiamrkit/alignment/__init__.py +0 -0
- {maldiamrkit-0.22.0 → maldiamrkit-0.22.1}/maldiamrkit/data/__init__.py +0 -0
- {maldiamrkit-0.22.0 → maldiamrkit-0.22.1}/maldiamrkit/data/breakpoints/eucast/README.md +0 -0
- {maldiamrkit-0.22.0 → maldiamrkit-0.22.1}/maldiamrkit/data/breakpoints/eucast/eucast_v1.0.yaml +0 -0
- {maldiamrkit-0.22.0 → maldiamrkit-0.22.1}/maldiamrkit/data/breakpoints/eucast/eucast_v1.1.yaml +0 -0
- {maldiamrkit-0.22.0 → maldiamrkit-0.22.1}/maldiamrkit/data/breakpoints/eucast/eucast_v1.2.yaml +0 -0
- {maldiamrkit-0.22.0 → maldiamrkit-0.22.1}/maldiamrkit/data/breakpoints/eucast/eucast_v1.3.yaml +0 -0
- {maldiamrkit-0.22.0 → maldiamrkit-0.22.1}/maldiamrkit/data/breakpoints/eucast/eucast_v10.0.yaml +0 -0
- {maldiamrkit-0.22.0 → maldiamrkit-0.22.1}/maldiamrkit/data/breakpoints/eucast/eucast_v11.0.yaml +0 -0
- {maldiamrkit-0.22.0 → maldiamrkit-0.22.1}/maldiamrkit/data/breakpoints/eucast/eucast_v12.0.yaml +0 -0
- {maldiamrkit-0.22.0 → maldiamrkit-0.22.1}/maldiamrkit/data/breakpoints/eucast/eucast_v13.1.yaml +0 -0
- {maldiamrkit-0.22.0 → maldiamrkit-0.22.1}/maldiamrkit/data/breakpoints/eucast/eucast_v14.0.yaml +0 -0
- {maldiamrkit-0.22.0 → maldiamrkit-0.22.1}/maldiamrkit/data/breakpoints/eucast/eucast_v15.0.yaml +0 -0
- {maldiamrkit-0.22.0 → maldiamrkit-0.22.1}/maldiamrkit/data/breakpoints/eucast/eucast_v16.0.yaml +0 -0
- {maldiamrkit-0.22.0 → maldiamrkit-0.22.1}/maldiamrkit/data/breakpoints/eucast/eucast_v2.0.yaml +0 -0
- {maldiamrkit-0.22.0 → maldiamrkit-0.22.1}/maldiamrkit/data/breakpoints/eucast/eucast_v4.0.yaml +0 -0
- {maldiamrkit-0.22.0 → maldiamrkit-0.22.1}/maldiamrkit/data/breakpoints/eucast/eucast_v5.0.yaml +0 -0
- {maldiamrkit-0.22.0 → maldiamrkit-0.22.1}/maldiamrkit/data/breakpoints/eucast/eucast_v6.0.yaml +0 -0
- {maldiamrkit-0.22.0 → maldiamrkit-0.22.1}/maldiamrkit/data/breakpoints/eucast/eucast_v7.1.yaml +0 -0
- {maldiamrkit-0.22.0 → maldiamrkit-0.22.1}/maldiamrkit/data/breakpoints/eucast/eucast_v8.0.yaml +0 -0
- {maldiamrkit-0.22.0 → maldiamrkit-0.22.1}/maldiamrkit/data/breakpoints/eucast/eucast_v8.1.yaml +0 -0
- {maldiamrkit-0.22.0 → maldiamrkit-0.22.1}/maldiamrkit/data/breakpoints/eucast/eucast_v9.0.yaml +0 -0
- {maldiamrkit-0.22.0 → maldiamrkit-0.22.1}/maldiamrkit/data/breakpoints/example.yaml +0 -0
- {maldiamrkit-0.22.0 → maldiamrkit-0.22.1}/maldiamrkit/data/site_info.py +0 -0
- {maldiamrkit-0.22.0 → maldiamrkit-0.22.1}/maldiamrkit/detection/__init__.py +0 -0
- {maldiamrkit-0.22.0 → maldiamrkit-0.22.1}/maldiamrkit/differential/__init__.py +0 -0
- {maldiamrkit-0.22.0 → maldiamrkit-0.22.1}/maldiamrkit/differential/plots.py +0 -0
- {maldiamrkit-0.22.0 → maldiamrkit-0.22.1}/maldiamrkit/differential/stats.py +0 -0
- {maldiamrkit-0.22.0 → maldiamrkit-0.22.1}/maldiamrkit/drift/__init__.py +0 -0
- {maldiamrkit-0.22.0 → maldiamrkit-0.22.1}/maldiamrkit/drift/pca_drift.py +0 -0
- {maldiamrkit-0.22.0 → maldiamrkit-0.22.1}/maldiamrkit/drift/plots.py +0 -0
- {maldiamrkit-0.22.0 → maldiamrkit-0.22.1}/maldiamrkit/drift/reference.py +0 -0
- {maldiamrkit-0.22.0 → maldiamrkit-0.22.1}/maldiamrkit/evaluation/__init__.py +0 -0
- {maldiamrkit-0.22.0 → maldiamrkit-0.22.1}/maldiamrkit/io/__init__.py +0 -0
- {maldiamrkit-0.22.0 → maldiamrkit-0.22.1}/maldiamrkit/io/mic.py +0 -0
- {maldiamrkit-0.22.0 → maldiamrkit-0.22.1}/maldiamrkit/io/writers.py +0 -0
- {maldiamrkit-0.22.0 → maldiamrkit-0.22.1}/maldiamrkit/preprocessing/__init__.py +0 -0
- {maldiamrkit-0.22.0 → maldiamrkit-0.22.1}/maldiamrkit/preprocessing/pipeline.py +0 -0
- {maldiamrkit-0.22.0 → maldiamrkit-0.22.1}/maldiamrkit/preprocessing/preprocessing_pipeline.py +0 -0
- {maldiamrkit-0.22.0 → maldiamrkit-0.22.1}/maldiamrkit/py.typed +0 -0
- {maldiamrkit-0.22.0 → maldiamrkit-0.22.1}/maldiamrkit/similarity/__init__.py +0 -0
- {maldiamrkit-0.22.0 → maldiamrkit-0.22.1}/maldiamrkit/similarity/clustering.py +0 -0
- {maldiamrkit-0.22.0 → maldiamrkit-0.22.1}/maldiamrkit/similarity/metrics.py +0 -0
- {maldiamrkit-0.22.0 → maldiamrkit-0.22.1}/maldiamrkit/similarity/pairwise.py +0 -0
- {maldiamrkit-0.22.0 → maldiamrkit-0.22.1}/maldiamrkit/similarity/plots.py +0 -0
- {maldiamrkit-0.22.0 → maldiamrkit-0.22.1}/maldiamrkit/spectrum.py +0 -0
- {maldiamrkit-0.22.0 → maldiamrkit-0.22.1}/maldiamrkit/susceptibility/__init__.py +0 -0
- {maldiamrkit-0.22.0 → maldiamrkit-0.22.1}/maldiamrkit/visualization/__init__.py +0 -0
- {maldiamrkit-0.22.0 → maldiamrkit-0.22.1}/maldiamrkit/visualization/_common.py +0 -0
- {maldiamrkit-0.22.0 → maldiamrkit-0.22.1}/maldiamrkit/visualization/alignment_plots.py +0 -0
- {maldiamrkit-0.22.0 → maldiamrkit-0.22.1}/maldiamrkit/visualization/exploratory_plots.py +0 -0
- {maldiamrkit-0.22.0 → maldiamrkit-0.22.1}/maldiamrkit/visualization/peak_plots.py +0 -0
- {maldiamrkit-0.22.0 → maldiamrkit-0.22.1}/maldiamrkit/visualization/spectrum_plots.py +0 -0
- {maldiamrkit-0.22.0 → maldiamrkit-0.22.1}/pyproject.toml +0 -0
- {maldiamrkit-0.22.0 → maldiamrkit-0.22.1}/requirements-batch.txt +0 -0
- {maldiamrkit-0.22.0 → maldiamrkit-0.22.1}/requirements-dev.txt +0 -0
- {maldiamrkit-0.22.0 → maldiamrkit-0.22.1}/requirements-docs.txt +0 -0
- {maldiamrkit-0.22.0 → maldiamrkit-0.22.1}/requirements-formats.txt +0 -0
- {maldiamrkit-0.22.0 → maldiamrkit-0.22.1}/setup.cfg +0 -0
- {maldiamrkit-0.22.0 → maldiamrkit-0.22.1}/tests/test_compat.py +0 -0
- {maldiamrkit-0.22.0 → maldiamrkit-0.22.1}/tests/test_numerical_edge_cases.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: MaldiAMRKit
|
|
3
|
-
Version: 0.22.
|
|
3
|
+
Version: 0.22.1
|
|
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
|
|
@@ -31,6 +31,7 @@ Requires-Dist: seaborn>=0.11.0
|
|
|
31
31
|
Requires-Dist: pybaselines>=1.0.0
|
|
32
32
|
Requires-Dist: gudhi>=3.5.0
|
|
33
33
|
Requires-Dist: tslearn>=0.6.0
|
|
34
|
+
Requires-Dist: numba>=0.55
|
|
34
35
|
Requires-Dist: pyyaml>=6.0
|
|
35
36
|
Requires-Dist: pyarrow>=14.0.0
|
|
36
37
|
Requires-Dist: typer>=0.9.0
|
|
@@ -143,7 +144,7 @@ pip install -e .[dev]
|
|
|
143
144
|
- **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
145
|
- **Peak Detection**: Local maxima and persistent homology methods
|
|
145
146
|
- **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
|
-
- **Fit-Free Peak Alignment**: `align_peaks()` warps a peak set onto caller-supplied reference peaks,
|
|
147
|
+
- **Fit-Free Peak Alignment**: `align_peaks()` warps a peak set onto caller-supplied reference peaks, which the caller estimates on the training split (for example `RawWarping(...).fit(X_train).ref_peaks_mz_`; a reference built with test spectra leaks)
|
|
147
148
|
|
|
148
149
|
### Extensibility
|
|
149
150
|
- **Component Registries**: Plug your own components into the name-dispatched machinery - `register_spectral_metric()` for distance metrics (usable in `spectral_distance`, `pairwise_distances`, and `DriftMonitor`), `register_transformer()` to make `PreprocessingPipeline` configs holding custom transformers round-trip through JSON/YAML, and `register_binning_method()` for custom bin edges
|
|
@@ -162,7 +163,7 @@ pip install -e .[dev]
|
|
|
162
163
|
|
|
163
164
|
### Differential Analysis
|
|
164
165
|
- **`DifferentialAnalysis`**: Per-bin statistical testing (Mann-Whitney U, Welch's t-test) between resistant and susceptible groups, with multiple-testing correction, log2 fold change, and Cohen's d effect size
|
|
165
|
-
- **Peak
|
|
166
|
+
- **Peak Ranking**: `top_peaks()` by adjusted p-value, `significant_peaks()` with fold-change and p-value thresholds, `compare_drugs()` for multi-drug boolean significance matrices (to select features for a classifier, rank peaks inside each training fold)
|
|
166
167
|
- **AMR-Aware Plots**: `plot_volcano()`, `plot_manhattan()` along the m/z axis, and `plot_drug_comparison()` with binary heatmap or UpSet-style intersection view
|
|
167
168
|
|
|
168
169
|
### Drift Monitoring
|
|
@@ -246,7 +247,7 @@ pipe = Pipeline([
|
|
|
246
247
|
("clf", RandomForestClassifier(n_estimators=100, random_state=42))
|
|
247
248
|
])
|
|
248
249
|
|
|
249
|
-
# Cross-validation
|
|
250
|
+
# Cross-validation (with replicates, use StratifiedGroupKFold and groups=data.groups)
|
|
250
251
|
scores = cross_val_score(pipe, X, y, cv=5, scoring="accuracy")
|
|
251
252
|
print(f"CV Accuracy: {scores.mean():.3f} +/- {scores.std():.3f}")
|
|
252
253
|
```
|
|
@@ -21,11 +21,14 @@ maldiamrkit/filters.py
|
|
|
21
21
|
maldiamrkit/py.typed
|
|
22
22
|
maldiamrkit/spectrum.py
|
|
23
23
|
maldiamrkit/alignment/__init__.py
|
|
24
|
+
maldiamrkit/alignment/_dtw.py
|
|
25
|
+
maldiamrkit/alignment/_versioning.py
|
|
24
26
|
maldiamrkit/alignment/peak_align.py
|
|
25
27
|
maldiamrkit/alignment/raw_warping.py
|
|
26
28
|
maldiamrkit/alignment/strategies.py
|
|
27
29
|
maldiamrkit/alignment/warping.py
|
|
28
30
|
maldiamrkit/data/__init__.py
|
|
31
|
+
maldiamrkit/data/_metadata.py
|
|
29
32
|
maldiamrkit/data/builder.py
|
|
30
33
|
maldiamrkit/data/dataset_layouts.py
|
|
31
34
|
maldiamrkit/data/duplicates.py
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: MaldiAMRKit
|
|
3
|
-
Version: 0.22.
|
|
3
|
+
Version: 0.22.1
|
|
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
|
|
@@ -31,6 +31,7 @@ Requires-Dist: seaborn>=0.11.0
|
|
|
31
31
|
Requires-Dist: pybaselines>=1.0.0
|
|
32
32
|
Requires-Dist: gudhi>=3.5.0
|
|
33
33
|
Requires-Dist: tslearn>=0.6.0
|
|
34
|
+
Requires-Dist: numba>=0.55
|
|
34
35
|
Requires-Dist: pyyaml>=6.0
|
|
35
36
|
Requires-Dist: pyarrow>=14.0.0
|
|
36
37
|
Requires-Dist: typer>=0.9.0
|
|
@@ -143,7 +144,7 @@ pip install -e .[dev]
|
|
|
143
144
|
- **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
145
|
- **Peak Detection**: Local maxima and persistent homology methods
|
|
145
146
|
- **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
|
-
- **Fit-Free Peak Alignment**: `align_peaks()` warps a peak set onto caller-supplied reference peaks,
|
|
147
|
+
- **Fit-Free Peak Alignment**: `align_peaks()` warps a peak set onto caller-supplied reference peaks, which the caller estimates on the training split (for example `RawWarping(...).fit(X_train).ref_peaks_mz_`; a reference built with test spectra leaks)
|
|
147
148
|
|
|
148
149
|
### Extensibility
|
|
149
150
|
- **Component Registries**: Plug your own components into the name-dispatched machinery - `register_spectral_metric()` for distance metrics (usable in `spectral_distance`, `pairwise_distances`, and `DriftMonitor`), `register_transformer()` to make `PreprocessingPipeline` configs holding custom transformers round-trip through JSON/YAML, and `register_binning_method()` for custom bin edges
|
|
@@ -162,7 +163,7 @@ pip install -e .[dev]
|
|
|
162
163
|
|
|
163
164
|
### Differential Analysis
|
|
164
165
|
- **`DifferentialAnalysis`**: Per-bin statistical testing (Mann-Whitney U, Welch's t-test) between resistant and susceptible groups, with multiple-testing correction, log2 fold change, and Cohen's d effect size
|
|
165
|
-
- **Peak
|
|
166
|
+
- **Peak Ranking**: `top_peaks()` by adjusted p-value, `significant_peaks()` with fold-change and p-value thresholds, `compare_drugs()` for multi-drug boolean significance matrices (to select features for a classifier, rank peaks inside each training fold)
|
|
166
167
|
- **AMR-Aware Plots**: `plot_volcano()`, `plot_manhattan()` along the m/z axis, and `plot_drug_comparison()` with binary heatmap or UpSet-style intersection view
|
|
167
168
|
|
|
168
169
|
### Drift Monitoring
|
|
@@ -246,7 +247,7 @@ pipe = Pipeline([
|
|
|
246
247
|
("clf", RandomForestClassifier(n_estimators=100, random_state=42))
|
|
247
248
|
])
|
|
248
249
|
|
|
249
|
-
# Cross-validation
|
|
250
|
+
# Cross-validation (with replicates, use StratifiedGroupKFold and groups=data.groups)
|
|
250
251
|
scores = cross_val_score(pipe, X, y, cv=5, scoring="accuracy")
|
|
251
252
|
print(f"CV Accuracy: {scores.mean():.3f} +/- {scores.std():.3f}")
|
|
252
253
|
```
|
|
@@ -82,7 +82,7 @@ pip install -e .[dev]
|
|
|
82
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
|
-
- **Fit-Free Peak Alignment**: `align_peaks()` warps a peak set onto caller-supplied reference peaks,
|
|
85
|
+
- **Fit-Free Peak Alignment**: `align_peaks()` warps a peak set onto caller-supplied reference peaks, which the caller estimates on the training split (for example `RawWarping(...).fit(X_train).ref_peaks_mz_`; a reference built with test spectra leaks)
|
|
86
86
|
|
|
87
87
|
### Extensibility
|
|
88
88
|
- **Component Registries**: Plug your own components into the name-dispatched machinery - `register_spectral_metric()` for distance metrics (usable in `spectral_distance`, `pairwise_distances`, and `DriftMonitor`), `register_transformer()` to make `PreprocessingPipeline` configs holding custom transformers round-trip through JSON/YAML, and `register_binning_method()` for custom bin edges
|
|
@@ -101,7 +101,7 @@ pip install -e .[dev]
|
|
|
101
101
|
|
|
102
102
|
### Differential Analysis
|
|
103
103
|
- **`DifferentialAnalysis`**: Per-bin statistical testing (Mann-Whitney U, Welch's t-test) between resistant and susceptible groups, with multiple-testing correction, log2 fold change, and Cohen's d effect size
|
|
104
|
-
- **Peak
|
|
104
|
+
- **Peak Ranking**: `top_peaks()` by adjusted p-value, `significant_peaks()` with fold-change and p-value thresholds, `compare_drugs()` for multi-drug boolean significance matrices (to select features for a classifier, rank peaks inside each training fold)
|
|
105
105
|
- **AMR-Aware Plots**: `plot_volcano()`, `plot_manhattan()` along the m/z axis, and `plot_drug_comparison()` with binary heatmap or UpSet-style intersection view
|
|
106
106
|
|
|
107
107
|
### Drift Monitoring
|
|
@@ -185,7 +185,7 @@ pipe = Pipeline([
|
|
|
185
185
|
("clf", RandomForestClassifier(n_estimators=100, random_state=42))
|
|
186
186
|
])
|
|
187
187
|
|
|
188
|
-
# Cross-validation
|
|
188
|
+
# Cross-validation (with replicates, use StratifiedGroupKFold and groups=data.groups)
|
|
189
189
|
scores = cross_val_score(pipe, X, y, cv=5, scoring="accuracy")
|
|
190
190
|
print(f"CV Accuracy: {scores.mean():.3f} +/- {scores.std():.3f}")
|
|
191
191
|
```
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
"""Banded Sakoe-Chiba DTW path, computed on the band only.
|
|
2
|
+
|
|
3
|
+
The path is the one :func:`tslearn.metrics.dtw_path` returns for two series
|
|
4
|
+
of equal length with ``global_constraint="sakoe_chiba"``: same float64 cost,
|
|
5
|
+
same tie order when walking back. Memory is ``O(n * (2 * radius + 1))``
|
|
6
|
+
instead of tslearn's ``O(n ** 2)``.
|
|
7
|
+
"""
|
|
8
|
+
|
|
9
|
+
from __future__ import annotations
|
|
10
|
+
|
|
11
|
+
import numpy as np
|
|
12
|
+
from numba import njit
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
@njit(cache=True, nogil=True)
|
|
16
|
+
def _banded_path(s1, s2, radius):
|
|
17
|
+
"""Forward DTW path ``(path_i, path_j)`` of two float64 series of length n."""
|
|
18
|
+
n = s1.shape[0]
|
|
19
|
+
r = min(radius, n - 1)
|
|
20
|
+
w = 2 * r + 1
|
|
21
|
+
# cost[i, k] is the accumulated cost of cell (i, j) with j = i - r + k.
|
|
22
|
+
cost = np.full((n, w), np.inf)
|
|
23
|
+
for i in range(n):
|
|
24
|
+
lo = max(0, i - r)
|
|
25
|
+
hi = min(n - 1, i + r)
|
|
26
|
+
for j in range(lo, hi + 1):
|
|
27
|
+
k = j - i + r
|
|
28
|
+
if i == 0 and j == 0:
|
|
29
|
+
best = 0.0
|
|
30
|
+
else:
|
|
31
|
+
up = cost[i - 1, k + 1] if i > 0 and k + 1 < w else np.inf
|
|
32
|
+
left = cost[i, k - 1] if j > 0 and k > 0 else np.inf
|
|
33
|
+
diag = cost[i - 1, k] if i > 0 and j > 0 else np.inf
|
|
34
|
+
best = min(up, left, diag)
|
|
35
|
+
diff = s1[i] - s2[j]
|
|
36
|
+
dist = diff * diff
|
|
37
|
+
cost[i, k] = dist + best
|
|
38
|
+
|
|
39
|
+
path_i = np.empty(2 * n, dtype=np.int64)
|
|
40
|
+
path_j = np.empty(2 * n, dtype=np.int64)
|
|
41
|
+
i = n - 1
|
|
42
|
+
j = n - 1
|
|
43
|
+
m = 0
|
|
44
|
+
path_i[0] = i
|
|
45
|
+
path_j[0] = j
|
|
46
|
+
while i != 0 or j != 0:
|
|
47
|
+
if i == 0:
|
|
48
|
+
j -= 1
|
|
49
|
+
elif j == 0:
|
|
50
|
+
i -= 1
|
|
51
|
+
else:
|
|
52
|
+
# Same order as tslearn: diagonal, then up, then left.
|
|
53
|
+
k = j - i + r
|
|
54
|
+
diag = cost[i - 1, k] if 0 <= k < w else np.inf
|
|
55
|
+
up = cost[i - 1, k + 1] if 0 <= k + 1 < w else np.inf
|
|
56
|
+
left = cost[i, k - 1] if 0 <= k - 1 < w else np.inf
|
|
57
|
+
if diag <= up and diag <= left:
|
|
58
|
+
i -= 1
|
|
59
|
+
j -= 1
|
|
60
|
+
elif up <= left:
|
|
61
|
+
i -= 1
|
|
62
|
+
else:
|
|
63
|
+
j -= 1
|
|
64
|
+
m += 1
|
|
65
|
+
path_i[m] = i
|
|
66
|
+
path_j[m] = j
|
|
67
|
+
return path_i[: m + 1][::-1].copy(), path_j[: m + 1][::-1].copy()
|
|
68
|
+
|
|
69
|
+
|
|
70
|
+
def _dtw_path(
|
|
71
|
+
query: np.ndarray, reference: np.ndarray, radius: int
|
|
72
|
+
) -> tuple[np.ndarray, np.ndarray]:
|
|
73
|
+
"""Banded DTW path of two series of equal length.
|
|
74
|
+
|
|
75
|
+
Both series are cast to contiguous float64 (as tslearn does), so the
|
|
76
|
+
kernel is compiled once whatever the input dtype.
|
|
77
|
+
"""
|
|
78
|
+
return _banded_path(
|
|
79
|
+
np.ascontiguousarray(query, dtype=np.float64),
|
|
80
|
+
np.ascontiguousarray(reference, dtype=np.float64),
|
|
81
|
+
int(radius),
|
|
82
|
+
)
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
"""Version stamp for pickled aligners.
|
|
2
|
+
|
|
3
|
+
A pickled :class:`~maldiamrkit.alignment.Warping` or
|
|
4
|
+
:class:`~maldiamrkit.alignment.RawWarping` records the maldiamrkit version it
|
|
5
|
+
was saved with. An aligner fitted with maldiamrkit 0.21 or earlier lacks the
|
|
6
|
+
parameters added in 0.22 and aligns differently, so it is refused instead of
|
|
7
|
+
being completed with defaults (which would align new spectra differently
|
|
8
|
+
from the training data).
|
|
9
|
+
"""
|
|
10
|
+
|
|
11
|
+
from __future__ import annotations
|
|
12
|
+
|
|
13
|
+
import re
|
|
14
|
+
import warnings
|
|
15
|
+
|
|
16
|
+
_PARAMS_SINCE_0_22 = (
|
|
17
|
+
"shift_estimator",
|
|
18
|
+
"min_gain",
|
|
19
|
+
"min_support",
|
|
20
|
+
"n_peaks",
|
|
21
|
+
"prealign",
|
|
22
|
+
"renormalize",
|
|
23
|
+
)
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
def _current_version() -> str:
|
|
27
|
+
import maldiamrkit
|
|
28
|
+
|
|
29
|
+
return maldiamrkit.__version__
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
def _version_tuple(text: object) -> tuple[int, int, int] | None:
|
|
33
|
+
"""Integers of the first three dotted fields of a version, or None."""
|
|
34
|
+
if not isinstance(text, str):
|
|
35
|
+
return None
|
|
36
|
+
match = re.match(r"\s*(\d+)\.(\d+)(?:\.(\d+))?", text)
|
|
37
|
+
if match is None:
|
|
38
|
+
return None
|
|
39
|
+
return tuple(int(part or 0) for part in match.groups())
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
def _versioned_state(state: dict) -> dict:
|
|
43
|
+
"""Stamp the pickled state with the running maldiamrkit version."""
|
|
44
|
+
return dict(state, _maldiamrkit_version=_current_version())
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
def _checked_state(name: str, state: dict) -> dict:
|
|
48
|
+
"""Return the state to restore, warning when it comes from an older release."""
|
|
49
|
+
state = dict(state)
|
|
50
|
+
version = state.pop("_maldiamrkit_version", None)
|
|
51
|
+
current = _current_version()
|
|
52
|
+
if any(param not in state for param in _PARAMS_SINCE_0_22):
|
|
53
|
+
message = (
|
|
54
|
+
f"This {name} was fitted with maldiamrkit 0.21 or earlier, whose "
|
|
55
|
+
f"alignment differs from maldiamrkit {current}: it must be refitted "
|
|
56
|
+
"(fit, transform and get_alignment_quality raise), or used with "
|
|
57
|
+
"maldiamrkit < 0.22."
|
|
58
|
+
)
|
|
59
|
+
elif version is None:
|
|
60
|
+
message = (
|
|
61
|
+
f"This {name} was pickled with maldiamrkit 0.22.0 or earlier, which "
|
|
62
|
+
f"did not record its version; it is loaded with maldiamrkit "
|
|
63
|
+
f"{current} and can still be used."
|
|
64
|
+
)
|
|
65
|
+
else:
|
|
66
|
+
saved, running = _version_tuple(version), _version_tuple(current)
|
|
67
|
+
if saved is not None and (running is None or saved >= running):
|
|
68
|
+
return state
|
|
69
|
+
message = (
|
|
70
|
+
f"This {name} was pickled with maldiamrkit {version} and is loaded "
|
|
71
|
+
f"with maldiamrkit {current}."
|
|
72
|
+
)
|
|
73
|
+
warnings.warn(message, UserWarning, stacklevel=3)
|
|
74
|
+
return state
|
|
75
|
+
|
|
76
|
+
|
|
77
|
+
def _check_supported(estimator: object) -> None:
|
|
78
|
+
"""Raise when ``estimator`` holds the state of maldiamrkit 0.21 or earlier."""
|
|
79
|
+
if all(hasattr(estimator, param) for param in _PARAMS_SINCE_0_22):
|
|
80
|
+
return
|
|
81
|
+
name = type(estimator).__name__
|
|
82
|
+
raise RuntimeError(
|
|
83
|
+
f"This {name} was fitted with maldiamrkit 0.21 or earlier, whose "
|
|
84
|
+
"alignment differs from maldiamrkit 0.22: create and fit a new "
|
|
85
|
+
f"{name} with the current version (or keep maldiamrkit < 0.22 to use "
|
|
86
|
+
"this one)."
|
|
87
|
+
)
|
|
@@ -62,7 +62,10 @@ def align_peaks(
|
|
|
62
62
|
peaks : PeakSet
|
|
63
63
|
Peak set to align.
|
|
64
64
|
ref_peaks_mz : array-like
|
|
65
|
-
Reference peak m/z positions to align to.
|
|
65
|
+
Reference peak m/z positions to align to. Estimate them on the
|
|
66
|
+
training spectra only (for example ``RawWarping(...).fit(X_train)``
|
|
67
|
+
and its ``ref_peaks_mz_``), so that test peak sets do not shape
|
|
68
|
+
their own reference.
|
|
66
69
|
method : {"shift", "linear", "piecewise", "quadratic", "cubic", "lowess"}, default="shift"
|
|
67
70
|
Warping strategy. ``"dtw"`` is unsupported for peak sets because it
|
|
68
71
|
resamples onto a dense grid and would destroy the set structure.
|
|
@@ -82,7 +85,8 @@ def align_peaks(
|
|
|
82
85
|
Returns
|
|
83
86
|
-------
|
|
84
87
|
PeakSet
|
|
85
|
-
A new peak set with warped m/z and unchanged intensities
|
|
88
|
+
A new peak set with warped m/z and unchanged intensities and
|
|
89
|
+
scores.
|
|
86
90
|
|
|
87
91
|
Raises
|
|
88
92
|
------
|
|
@@ -110,9 +114,10 @@ def align_peaks(
|
|
|
110
114
|
"'cubic', or 'lowess'."
|
|
111
115
|
)
|
|
112
116
|
|
|
117
|
+
score = None if peaks.score is None else peaks.score.copy()
|
|
113
118
|
ref_peaks_mz = np.asarray(ref_peaks_mz, dtype=float).ravel()
|
|
114
119
|
if peaks.n_peaks == 0 or ref_peaks_mz.size == 0:
|
|
115
|
-
return PeakSet(peaks.mz.copy(), peaks.intensity.copy())
|
|
120
|
+
return PeakSet(peaks.mz.copy(), peaks.intensity.copy(), score=score)
|
|
116
121
|
|
|
117
122
|
strategy = _build_strategy(
|
|
118
123
|
method, max_shift_da, n_segments, smooth_sigma, lowess_frac, lowess_it
|
|
@@ -125,4 +130,4 @@ def align_peaks(
|
|
|
125
130
|
ref_peaks_mz,
|
|
126
131
|
np.ones_like(ref_peaks_mz),
|
|
127
132
|
)
|
|
128
|
-
return PeakSet(np.asarray(new_mz, dtype=float), peaks.intensity.copy())
|
|
133
|
+
return PeakSet(np.asarray(new_mz, dtype=float), peaks.intensity.copy(), score=score)
|
|
@@ -13,9 +13,20 @@ from sklearn.base import BaseEstimator, TransformerMixin
|
|
|
13
13
|
from ..data.duplicates import DuplicateStrategy, apply_index_strategy
|
|
14
14
|
from ..detection.peak_detector import MaldiPeakDetector
|
|
15
15
|
from ..io.readers import read_spectrum
|
|
16
|
-
from ..preprocessing.binning import
|
|
16
|
+
from ..preprocessing.binning import (
|
|
17
|
+
_BINNING_REGISTRY,
|
|
18
|
+
BinningMethod,
|
|
19
|
+
_bin_on_edges,
|
|
20
|
+
bin_spectrum,
|
|
21
|
+
)
|
|
17
22
|
from ..preprocessing.pipeline import preprocess
|
|
18
23
|
from ..preprocessing.preprocessing_pipeline import PreprocessingPipeline
|
|
24
|
+
from ._versioning import (
|
|
25
|
+
_PARAMS_SINCE_0_22,
|
|
26
|
+
_check_supported,
|
|
27
|
+
_checked_state,
|
|
28
|
+
_versioned_state,
|
|
29
|
+
)
|
|
19
30
|
from .strategies import (
|
|
20
31
|
_ALIGNMENT_REGISTRY,
|
|
21
32
|
_SHIFT_ESTIMATORS,
|
|
@@ -56,10 +67,15 @@ def create_raw_input(
|
|
|
56
67
|
* ``"first"``: keep the first occurrence (default).
|
|
57
68
|
* ``"last"``: keep the last occurrence.
|
|
58
69
|
* ``"drop"``: remove all duplicates.
|
|
59
|
-
* ``"keep_all"``: keep every replicate
|
|
70
|
+
* ``"keep_all"``: keep every replicate, adding ``_repN`` to the
|
|
71
|
+
duplicated IDs (unique IDs stay unchanged).
|
|
60
72
|
* ``"average"``: keep all replicates and add an
|
|
61
73
|
``_original_id`` column so that
|
|
62
|
-
:meth:`RawWarping.transform` can group and average them
|
|
74
|
+
:meth:`RawWarping.transform` can group and average them (the
|
|
75
|
+
output then has one row per sample, so it cannot be used inside
|
|
76
|
+
``Pipeline.fit``, which needs one row per input row; when
|
|
77
|
+
splitting rows, keep the replicates of a sample together with
|
|
78
|
+
``groups=``).
|
|
63
79
|
|
|
64
80
|
Returns
|
|
65
81
|
-------
|
|
@@ -136,6 +152,8 @@ class RawWarping(BaseEstimator, TransformerMixin):
|
|
|
136
152
|
Width of output bins in Daltons.
|
|
137
153
|
bin_method : str, default="uniform"
|
|
138
154
|
Binning method. One of 'uniform', 'proportional', 'adaptive', 'custom'.
|
|
155
|
+
With 'adaptive', the edges are learned from the reference spectrum in
|
|
156
|
+
:meth:`fit` and used for every transformed spectrum.
|
|
139
157
|
bin_kwargs : dict, optional
|
|
140
158
|
Additional keyword arguments for binning.
|
|
141
159
|
max_shift_da : float, default=10.0
|
|
@@ -145,10 +163,8 @@ class RawWarping(BaseEstimator, TransformerMixin):
|
|
|
145
163
|
n_segments : int, default=5
|
|
146
164
|
Number of segments for piecewise warping.
|
|
147
165
|
dtw_radius : int, default=10
|
|
148
|
-
Radius constraint for DTW
|
|
149
|
-
|
|
150
|
-
grid over 2-20 kDa), so a coarser ``interp_step`` is needed to run
|
|
151
|
-
it on full-resolution spectra.
|
|
166
|
+
Radius constraint for DTW (Sakoe-Chiba band, in points of the
|
|
167
|
+
reference grid).
|
|
152
168
|
smooth_sigma : float, default=2.0
|
|
153
169
|
Gaussian smoothing for piecewise transitions.
|
|
154
170
|
lowess_frac : float, default=0.3
|
|
@@ -263,6 +279,10 @@ class RawWarping(BaseEstimator, TransformerMixin):
|
|
|
263
279
|
aligns each spectrum on its own (replicates of one sample are averaged
|
|
264
280
|
after alignment), so its result does not depend on the other spectra
|
|
265
281
|
transformed with it.
|
|
282
|
+
|
|
283
|
+
A pickled aligner records the maldiamrkit version it was saved with; one
|
|
284
|
+
fitted with maldiamrkit 0.21 or earlier cannot be used and must be
|
|
285
|
+
refitted.
|
|
266
286
|
"""
|
|
267
287
|
|
|
268
288
|
def __init__(
|
|
@@ -407,6 +427,32 @@ class RawWarping(BaseEstimator, TransformerMixin):
|
|
|
407
427
|
|
|
408
428
|
return ref_mz, ref_intensity, ref_peaks_mz
|
|
409
429
|
|
|
430
|
+
def __getstate__(self):
|
|
431
|
+
return _versioned_state(super().__getstate__())
|
|
432
|
+
|
|
433
|
+
def __setstate__(self, state):
|
|
434
|
+
super().__setstate__(_checked_state(type(self).__name__, state))
|
|
435
|
+
# Aligners pickled with 0.22.0 binned adaptively spectrum by spectrum:
|
|
436
|
+
# learn the edges from their reference, as fit does now.
|
|
437
|
+
if (
|
|
438
|
+
"_adaptive_edges_" not in self.__dict__
|
|
439
|
+
and hasattr(self, "ref_mz_")
|
|
440
|
+
and all(param in self.__dict__ for param in _PARAMS_SINCE_0_22)
|
|
441
|
+
):
|
|
442
|
+
self._adaptive_edges_ = self._learn_adaptive_edges()
|
|
443
|
+
if self._adaptive_edges_ is not None and not self._output_columns().equals(
|
|
444
|
+
self.output_columns_
|
|
445
|
+
):
|
|
446
|
+
self._adaptive_edges_ = None
|
|
447
|
+
self._stale_bins_ = True
|
|
448
|
+
warnings.warn(
|
|
449
|
+
"This RawWarping was pickled with maldiamrkit 0.22.0 and its "
|
|
450
|
+
"adaptive bins cannot be rebuilt exactly from its reference: "
|
|
451
|
+
"refit it before transforming.",
|
|
452
|
+
UserWarning,
|
|
453
|
+
stacklevel=2,
|
|
454
|
+
)
|
|
455
|
+
|
|
410
456
|
def fit(self, X: pd.DataFrame, y=None):
|
|
411
457
|
"""
|
|
412
458
|
Fit by computing the reference spectrum from raw data.
|
|
@@ -427,10 +473,14 @@ class RawWarping(BaseEstimator, TransformerMixin):
|
|
|
427
473
|
|
|
428
474
|
Raises
|
|
429
475
|
------
|
|
476
|
+
RuntimeError
|
|
477
|
+
If the transformer was fitted with maldiamrkit 0.21 or earlier
|
|
478
|
+
(loaded from an old pickle).
|
|
430
479
|
ValueError
|
|
431
480
|
If the input DataFrame is empty, lacks a 'path' column,
|
|
432
481
|
or uses an unknown warping method.
|
|
433
482
|
"""
|
|
483
|
+
_check_supported(self)
|
|
434
484
|
if X.empty:
|
|
435
485
|
raise ValueError("Input DataFrame X is empty")
|
|
436
486
|
|
|
@@ -454,6 +504,8 @@ class RawWarping(BaseEstimator, TransformerMixin):
|
|
|
454
504
|
|
|
455
505
|
# Store preprocessing config
|
|
456
506
|
self.pipeline_ = self.pipeline or PreprocessingPipeline.default()
|
|
507
|
+
self._adaptive_edges_ = None
|
|
508
|
+
self.__dict__.pop("_stale_bins_", None)
|
|
457
509
|
|
|
458
510
|
# Get paths from DataFrame
|
|
459
511
|
paths = X["path"].tolist()
|
|
@@ -484,12 +536,50 @@ class RawWarping(BaseEstimator, TransformerMixin):
|
|
|
484
536
|
stacklevel=2,
|
|
485
537
|
)
|
|
486
538
|
|
|
539
|
+
# Adaptive bins are learned once, from the reference, so that every
|
|
540
|
+
# transformed spectrum gets the same columns.
|
|
541
|
+
self._adaptive_edges_ = self._learn_adaptive_edges()
|
|
542
|
+
|
|
487
543
|
# Determine output columns by binning a sample spectrum
|
|
488
|
-
|
|
489
|
-
self.output_columns_ = sample_binned.set_index("mass").index.astype(str)
|
|
544
|
+
self.output_columns_ = self._output_columns()
|
|
490
545
|
|
|
491
546
|
return self
|
|
492
547
|
|
|
548
|
+
def _learn_adaptive_edges(self) -> np.ndarray | None:
|
|
549
|
+
"""Adaptive bin edges of the reference, or None for other methods.
|
|
550
|
+
|
|
551
|
+
The reference is binned with :func:`bin_spectrum`, which also checks
|
|
552
|
+
``bin_kwargs``.
|
|
553
|
+
"""
|
|
554
|
+
if _BINNING_REGISTRY.resolve_key(self.bin_method, BinningMethod) != "adaptive":
|
|
555
|
+
return None
|
|
556
|
+
mz_min, mz_max = self.pipeline_.mz_range
|
|
557
|
+
_, metadata = bin_spectrum(
|
|
558
|
+
pd.DataFrame({"mass": self.ref_mz_, "intensity": self.ref_intensity_}),
|
|
559
|
+
mz_min=mz_min,
|
|
560
|
+
mz_max=mz_max,
|
|
561
|
+
bin_width=self.bin_width,
|
|
562
|
+
method=self.bin_method,
|
|
563
|
+
**(self.bin_kwargs or {}),
|
|
564
|
+
)
|
|
565
|
+
return np.append(
|
|
566
|
+
metadata["bin_start"].to_numpy(dtype=float),
|
|
567
|
+
float(metadata["bin_end"].iloc[-1]),
|
|
568
|
+
)
|
|
569
|
+
|
|
570
|
+
def _output_columns(self) -> pd.Index:
|
|
571
|
+
"""Column labels of the binned output, from the reference."""
|
|
572
|
+
binned = self._bin_warped(self.ref_mz_, self.ref_intensity_)
|
|
573
|
+
return binned.set_index("mass").index.astype(str)
|
|
574
|
+
|
|
575
|
+
def _check_bins(self) -> None:
|
|
576
|
+
"""Raise when the adaptive bins of a 0.22.0 pickle could not be rebuilt."""
|
|
577
|
+
if getattr(self, "_stale_bins_", False):
|
|
578
|
+
raise RuntimeError(
|
|
579
|
+
"This RawWarping was pickled with maldiamrkit 0.22.0 and its "
|
|
580
|
+
"adaptive bins cannot be rebuilt exactly: refit it."
|
|
581
|
+
)
|
|
582
|
+
|
|
493
583
|
def _get_strategy(self):
|
|
494
584
|
"""Build strategy instance from current parameters."""
|
|
495
585
|
cls = _ALIGNMENT_REGISTRY[self.method]
|
|
@@ -554,6 +644,10 @@ class RawWarping(BaseEstimator, TransformerMixin):
|
|
|
554
644
|
def _bin_warped(self, mz: np.ndarray, intensity: np.ndarray) -> pd.DataFrame:
|
|
555
645
|
"""Bin warped raw spectrum to output grid."""
|
|
556
646
|
warped_df = pd.DataFrame({"mass": mz, "intensity": intensity})
|
|
647
|
+
adaptive_edges = getattr(self, "_adaptive_edges_", None)
|
|
648
|
+
if adaptive_edges is not None:
|
|
649
|
+
binned, _ = _bin_on_edges(warped_df, adaptive_edges)
|
|
650
|
+
return binned
|
|
557
651
|
bin_kwargs = self.bin_kwargs or {}
|
|
558
652
|
mz_min, mz_max = self.pipeline_.mz_range
|
|
559
653
|
binned, _ = bin_spectrum(
|
|
@@ -612,15 +706,21 @@ class RawWarping(BaseEstimator, TransformerMixin):
|
|
|
612
706
|
-------
|
|
613
707
|
X_aligned : pd.DataFrame
|
|
614
708
|
Aligned and binned spectra with sample IDs as index and
|
|
615
|
-
m/z bin centers as columns.
|
|
709
|
+
m/z bin centers as columns. With an ``_original_id`` column
|
|
710
|
+
(see :func:`create_raw_input`), replicates are averaged into
|
|
711
|
+
one row per sample, in order of first appearance.
|
|
616
712
|
|
|
617
713
|
Raises
|
|
618
714
|
------
|
|
619
715
|
RuntimeError
|
|
620
|
-
If the transformer has not been fitted
|
|
716
|
+
If the transformer has not been fitted, was fitted with
|
|
717
|
+
maldiamrkit 0.21 or earlier, or was pickled with 0.22.0 with
|
|
718
|
+
adaptive bins that cannot be rebuilt.
|
|
621
719
|
ValueError
|
|
622
720
|
If the input DataFrame lacks a 'path' column.
|
|
623
721
|
"""
|
|
722
|
+
_check_supported(self)
|
|
723
|
+
self._check_bins()
|
|
624
724
|
if not hasattr(self, "ref_mz_"):
|
|
625
725
|
raise RuntimeError("RawWarping must be fitted before transform")
|
|
626
726
|
|
|
@@ -648,7 +748,7 @@ class RawWarping(BaseEstimator, TransformerMixin):
|
|
|
648
748
|
if "_original_id" in X.columns:
|
|
649
749
|
original_ids = X["_original_id"]
|
|
650
750
|
result["_original_id"] = original_ids.values
|
|
651
|
-
averaged = result.groupby("_original_id").mean()
|
|
751
|
+
averaged = result.groupby("_original_id", sort=False).mean()
|
|
652
752
|
averaged.index.name = None
|
|
653
753
|
result = averaged
|
|
654
754
|
|
|
@@ -678,8 +778,12 @@ class RawWarping(BaseEstimator, TransformerMixin):
|
|
|
678
778
|
Raises
|
|
679
779
|
------
|
|
680
780
|
RuntimeError
|
|
681
|
-
If the transformer has not been fitted
|
|
781
|
+
If the transformer has not been fitted, was fitted with
|
|
782
|
+
maldiamrkit 0.21 or earlier, or was pickled with 0.22.0 with
|
|
783
|
+
adaptive bins that cannot be rebuilt.
|
|
682
784
|
"""
|
|
785
|
+
_check_supported(self)
|
|
786
|
+
self._check_bins()
|
|
683
787
|
if not hasattr(self, "ref_mz_"):
|
|
684
788
|
raise RuntimeError("RawWarping must be fitted first")
|
|
685
789
|
|