Feature Selection Diffusion#

diffusion #

CLASS DESCRIPTION
DiffusionSFS

Sequential feature selection for diffusion maps.

Classes#

DiffusionSFS(out_features: int = 0, kernel_fn: Kernel | str = 'gaussian', kernel_kwargs: dict | None = None, distance_fn: PairwiseDistance | str = 'euclidean', distance_kwargs: dict | None = None, score: Literal['eigenvalue_mse', 'gap_mse', 'gap_max'] = 'eigenvalue_mse', score_kwargs: dict | None = None, reference: torch.Tensor | None = None, n_states: int | None = None, forward: bool = True, floating: bool = False, labels: list[str] | None = None, n_cv: int = 5, n_jobs: int = -1, random_state: int | None = None) #

Bases: SequentialFeatureSelector

Sequential feature selection for diffusion maps.

Extends SequentialFeatureSelector with spectral scoring functions for diffusion map eigenvalue and spectral gap optimization.

PARAMETER DESCRIPTION
out_features

Target number of features to select.

TYPE: int, by default 0 DEFAULT: 0

kernel_fn

Kernel function or string identifier.

TYPE: Kernel | str, by default "gaussian" DEFAULT: 'gaussian'

kernel_kwargs

Keyword arguments for kernel function.

TYPE: dict | None, optional, by default None DEFAULT: None

distance_fn

Distance function or string identifier.

TYPE: PairwiseDistance | str, by default "euclidean" DEFAULT: 'euclidean'

distance_kwargs

Keyword arguments for distance function.

TYPE: dict | None, optional, by default None DEFAULT: None

score

Scoring function for feature selection.

TYPE: Literal["eigenvalue_mse", "gap_mse", "gap_max"], by default "eigenvalue_mse" DEFAULT: 'eigenvalue_mse'

score_kwargs

Keyword arguments for scoring function.

TYPE: dict | None, optional, by default None DEFAULT: None

reference

Reference eigenvalues for eigenvalue_mse and gap_mse scores.

TYPE: torch.Tensor | None, optional, by default None DEFAULT: None

n_states

Number of states for gap-based scores.

TYPE: int | None, optional, by default None DEFAULT: None

forward

If True, performs forward selection. If False, performs backward elimination.

TYPE: bool, by default True DEFAULT: True

floating

If True, enables floating variant.

TYPE: bool, by default False DEFAULT: False

labels

Optional feature names.

TYPE: list[str] | None, optional, by default None DEFAULT: None

n_cv

Cross-validation strategy.

TYPE: int | sklearn splitter, by default 5 DEFAULT: 5

n_jobs

Number of parallel jobs.

TYPE: int, by default -1 DEFAULT: -1

random_state

Random seed.

TYPE: int | None, optional, by default None DEFAULT: None

Source code in spectre/feature_selection/diffusion.py
def __init__(
    self,
    out_features: int = 0,
    kernel_fn: Kernel | str = "gaussian",
    kernel_kwargs: dict | None = None,
    distance_fn: PairwiseDistance | str = "euclidean",
    distance_kwargs: dict | None = None,
    score: Literal["eigenvalue_mse", "gap_mse", "gap_max"] = "eigenvalue_mse",
    score_kwargs: dict | None = None,
    reference: torch.Tensor | None = None,
    n_states: int | None = None,
    forward: bool = True,
    floating: bool = False,
    labels: list[str] | None = None,
    n_cv: int = 5,
    n_jobs: int = -1,
    random_state: int | None = None,
):
    # Validate score-specific parameters
    allowed_score = ["eigenvalue_mse", "gap_mse", "gap_max"]
    if score not in allowed_score:
        raise AttributeError(
            f"`{score} is not a valid `score`, choose from {allowed_score}."
        )

    if score in ["eigenvalue_mse", "gap_mse"]:
        if reference is None:
            raise AttributeError(f"Reference must be provided for `{score}`.")
        check_is_tensor(reference)
        self.reference = reference

    if score in ["gap_mse", "gap_max"]:
        if n_states is not None:
            if not isinstance(n_states, int):
                raise TypeError(
                    f"`n_eigen` must be an integer, got {type(n_states)}."
                )
            check_in_interval(n_states, "[1, inf)")

    if score_kwargs is None:
        score_kwargs = {}

    self.score_type = score

    # DiffusionMap is fitted in SequentialFeatureSelector. The score functions
    # (below) do not need to work with train and test data since they use attributes
    # calculated during `fit`.

    if score == "eigenvalue_mse":

        def score_fn(estimator: DiffusionMap, *args, **kwargs):
            min_eigen = min(len(estimator.eigenvalues), len(reference))
            return eigenvalue_reconstruction_error(
                eigenvalues=estimator.eigenvalues[:min_eigen],
                eigenvalues_target=reference[:min_eigen],
                **score_kwargs,
            )

    elif score == "gap_mse":

        def score_fn(estimator: DiffusionMap, *args, **kwargs):
            min_eigen = min(len(estimator.eigenvalues), len(reference))
            return spectral_gap_preservation(
                eigenvalues=estimator.eigenvalues[:min_eigen],
                eigenvalues_target=reference[:min_eigen],
                n_states=n_states,
                **score_kwargs,
            )

    elif score == "gap_max":

        def score_fn(estimator: DiffusionMap, *args, **kwargs):
            return spectral_gap(
                eigenvalues=estimator.eigenvalues,
                n_states=n_states,
                **score_kwargs,
            )

    maximize = score == "gap_max"

    estimator = DiffusionMap(
        kernel_fn=kernel_fn,
        kernel_kwargs=kernel_kwargs,
        distance_fn=distance_fn,
        distance_kwargs=distance_kwargs,
    )

    super().__init__(
        estimator=estimator,
        score_fn=score_fn,
        out_features=out_features,
        forward=forward,
        floating=floating,
        labels=labels,
        n_cv=n_cv,
        n_jobs=n_jobs,
        maximize=maximize,
        random_state=random_state,
    )

Functions#