Source code for modeva.data.feature_engineering.rotation

import copy
from typing import Tuple, Union

import numpy as np
import pandas as pd

from ...utils.constants import NUMERICAL
from ...utils.results import ValidationResult


[docs] class FEWhitening: def __init__(self, dataset): self.dataset = dataset self.key = "data_fe_whitening" self.fitted_ = False
[docs] def transform(self, data): if isinstance(data, pd.DataFrame): X = data[self.feature_names_in_].values.astype(np.float32) else: data = pd.DataFrame(data, columns=self.all_feature_names_in_) X = data[self.feature_names_in_].values.astype(np.float32) result = self.gaml_transformer_.transform(X) return pd.DataFrame(result, columns=self.feature_names_out_)
[docs] def run(self, features: Union[str, Tuple] = None, dataset: str = "main", regularization: float = 1e-8): """Applies rotor whitening (GA Mahalanobis transformation). Aligns data with principal axes using SVD-based whitening: X' = (X - mu) @ V @ diag(1/sigma) Parameters ---------- features : str or tuple, default=None Features to whiten. If None, all numerical features are used. dataset : {"main", "train", "test"}, default="main" Dataset used to fit the transformer. regularization : float, default=1e-8 Regularization for variance computation. """ from .gaml.rotation import RotorWhitening inputs = locals() inputs.pop('self', None) if features is None: features = [fn for fn, ft in zip(self.dataset.all_feature_names, self.dataset.all_feature_types) if ft == NUMERICAL] if isinstance(features, str): features = [features] self.all_feature_names_in_ = copy.copy(self.dataset.all_feature_names) self.feature_names_in_ = list(features) data = self.dataset.get_data(dataset=dataset) feature_indices = [self.dataset.all_feature_names.index(fn) for fn in features] X = data[:, feature_indices].astype(np.float32) self.gaml_transformer_ = RotorWhitening(regularization=regularization) self.gaml_transformer_.fit(X) self.feature_names_out_ = [f"wh_{fn}" for fn in features] self.fitted_ = True result = ValidationResult(key=self.key, data=self.dataset.name, inputs=inputs, value={"n_features_out": len(self.feature_names_out_), "feature_names_out": self.feature_names_out_}) return result
[docs] class FEShear: def __init__(self, dataset): self.dataset = dataset self.key = "data_fe_shear" self.fitted_ = False
[docs] def transform(self, data): if isinstance(data, pd.DataFrame): X = data[self.feature_names_in_].values.astype(np.float32) else: data = pd.DataFrame(data, columns=self.all_feature_names_in_) X = data[self.feature_names_in_].values.astype(np.float32) result = self.gaml_transformer_.transform(X) return pd.DataFrame(result, columns=self.feature_names_out_)
[docs] def run(self, features: Union[str, Tuple] = None, dataset: str = "main", threshold: float = 0.0): """Applies pairwise shear (decorrelation via residualization). For each feature pair (i, j): X_i' = X_i - beta_ij * X_j, where beta_ij = cov(X_i, X_j) / var(X_j). Parameters ---------- features : str or tuple, default=None Features to decorrelate. If None, all numerical features are used. dataset : {"main", "train", "test"}, default="main" Dataset used to fit the transformer. threshold : float, default=0.0 Only apply shear if |beta_ij| > threshold. """ from .gaml.shear import PairwiseShear inputs = locals() inputs.pop('self', None) if features is None: features = [fn for fn, ft in zip(self.dataset.all_feature_names, self.dataset.all_feature_types) if ft == NUMERICAL] if isinstance(features, str): features = [features] self.all_feature_names_in_ = copy.copy(self.dataset.all_feature_names) self.feature_names_in_ = list(features) data = self.dataset.get_data(dataset=dataset) feature_indices = [self.dataset.all_feature_names.index(fn) for fn in features] X = data[:, feature_indices].astype(np.float32) self.gaml_transformer_ = PairwiseShear(threshold=threshold) self.gaml_transformer_.fit(X) self.feature_names_out_ = [f"sh_{fn}" for fn in features] self.fitted_ = True result = ValidationResult(key=self.key, data=self.dataset.name, inputs=inputs, value={"n_features_out": len(self.feature_names_out_), "feature_names_out": self.feature_names_out_}) return result