import copy
from typing import Tuple, Union, List
import numpy as np
import pandas as pd
from ...utils.constants import NUMERICAL
from ...utils.results import ValidationResult
[docs]
class FEGradeRatio:
def __init__(self, dataset):
self.dataset = dataset
self.key = "data_fe_grade_ratio"
self.fitted_ = False
[docs]
def run(self,
features: Union[str, Tuple] = None,
dataset: str = "main",
max_triplets: int = 50,
regularization: float = 1e-8):
"""Generates grade-ratio shape feature measuring 3-way vs 2-way interaction complexity.
After whitening, computes ratio E3/E2 where E2 is summed pairwise blade energy
and E3 is summed triplet blade energy. High ratio = dominant 3-body structure.
Parameters
----------
features : str or tuple, default=None
Features to use. If None, all numerical features are used.
dataset : {"main", "train", "test"}, default="main"
Dataset used to fit the transformer.
max_triplets : int, default=50
Maximum number of sampled triplets for E3 estimation.
regularization : float, default=1e-8
Regularization for the internal whitening step.
"""
from .gaml.shape import GradeRatioShape
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_ = GradeRatioShape(max_triplets=max_triplets,
regularization=regularization)
self.gaml_transformer_.fit(X)
self.feature_names_out_ = self.gaml_transformer_.get_feature_names()
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 FEMultiGradeShape:
def __init__(self, dataset):
self.dataset = dataset
self.key = "data_fe_multi_grade_shape"
self.fitted_ = False
[docs]
def run(self,
features: Union[str, Tuple] = None,
dataset: str = "main",
grades: List[int] = None,
n_bins: int = 5,
regularization: float = 1e-8):
"""Generates multi-grade shape features (context distances using grades 2-4).
Computes Mahalanobis (grade 2), skewness-weighted (grade 3), and
kurtosis-weighted (grade 4) distances to class or quantile-bin centroids.
Requires a target variable.
Parameters
----------
features : str or tuple, default=None
Features to use. If None, all numerical features are used.
dataset : {"main", "train", "test"}, default="main"
Dataset used to fit the transformer.
grades : list of int, default=None
Which grades to include (2, 3, and/or 4). Defaults to [2].
n_bins : int, default=5
Number of bins for regression (uses quantiles).
regularization : float, default=1e-8
Regularization for covariance inversion.
"""
from .gaml.shape import MultiGradeShape
inputs = locals()
inputs.pop('self', None)
if grades is None:
grades = [2]
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)
# Get target for supervised fitting
y_idx = self.dataset.target_feature_index
y = data[:, y_idx].astype(np.float64).ravel()
self.gaml_transformer_ = MultiGradeShape(grades=grades,
n_bins=n_bins,
regularization=regularization)
self.gaml_transformer_.fit(X, y)
self.feature_names_out_ = self.gaml_transformer_.get_feature_names()
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