Source code for maldideepkit.uncertainty._base
"""Abstract base class shared by every uncertainty estimator."""
from __future__ import annotations
from abc import ABCMeta, abstractmethod
from typing import Any
import numpy as np
from sklearn.utils.validation import check_is_fitted
from ..base.classifier import BaseSpectralClassifier
from ..base.data import _to_numpy
from ._result import UncertaintyResult
def _apply_classifier_preprocessing(
classifier: BaseSpectralClassifier, X: Any
) -> np.ndarray:
"""Apply the classifier's full inference-time preprocessing to ``X``.
Mirrors the preprocessing performed inside
:meth:`BaseSpectralClassifier._forward_logits` exactly: optional
spectral warping, the fitted ``input_transform`` state, and the
legacy ``standardize`` path used when no modern input transform is
set. Replicating it here lets uncertainty estimators feed data
through ``classifier.model_`` directly without going through the
eval-only ``_forward_logits`` shortcut.
Parameters
----------
classifier : BaseSpectralClassifier
Fitted classifier whose preprocessing artefacts will be applied.
X : array-like or MaldiSet of shape (n_samples, n_bins)
Raw input spectra.
Returns
-------
ndarray of shape (n_samples, n_bins)
Preprocessed feature matrix as ``float32``.
"""
X_np = _to_numpy(X)
classifier._check_input_dim(X_np)
if getattr(classifier, "warper_", None) is not None:
from ..base.data import _warp_numpy
X_np = _warp_numpy(classifier.warper_, X_np)
state = getattr(classifier, "input_transform_state_", None)
if state is not None and state.get("mode", "none") != "none":
from ..base.data import apply_input_transform
X_np = apply_input_transform(X_np, state)
elif (
classifier.standardize
and getattr(classifier, "feature_mean_", None) is not None
):
from ..base.data import _STD_FLOOR
safe_std = np.maximum(classifier.feature_std_, _STD_FLOOR).astype(np.float32)
X_np = (X_np - classifier.feature_mean_) / safe_std
return X_np.astype(np.float32, copy=False)
[docs]
class BaseUncertaintyEstimator(metaclass=ABCMeta):
"""Abstract base for every estimator in :mod:`maldideepkit.uncertainty`.
Parameters
----------
classifier : BaseSpectralClassifier
A *fitted* MaldiDeepKit classifier. Its preprocessing pipeline
(warping, input transform, legacy standardisation) is reused so
the uncertainty estimate is produced on inputs identical to
those seen at training time.
Raises
------
sklearn.exceptions.NotFittedError
If ``classifier`` has not been fitted.
"""
[docs]
def __init__(self, classifier: BaseSpectralClassifier) -> None:
check_is_fitted(classifier, "model_")
self.classifier = classifier
[docs]
@abstractmethod
def predict_with_uncertainty(self, X: Any) -> UncertaintyResult:
"""Return predictions and per-sample uncertainty for ``X``.
Parameters
----------
X : array-like or MaldiSet of shape (n_samples, n_bins)
Spectra to score. Must match ``classifier.input_dim_``.
Returns
-------
UncertaintyResult
Predictions, probability mean, scalar uncertainty, optional
epistemic / aleatoric decomposition, and method-specific
metadata.
"""
def __repr__(self) -> str:
return f"{type(self).__name__}(classifier={type(self.classifier).__name__})"
__all__ = ["BaseUncertaintyEstimator"]