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 FEDensity:
def __init__(self, dataset):
self.dataset = dataset
self.key = "data_fe_density"
self.fitted_ = False
[docs]
def run(self,
features: Union[str, Tuple] = None,
dataset: str = "main",
bandwidth: Union[str, float] = "median",
n_reference: int = 500,
log_density: bool = True):
"""Generates RBF kernel density feature per sample.
Computes mean RBF similarity to a reference subset of training points,
yielding a scalar density estimate per row.
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.
bandwidth : str or float, default="median"
If 'median', sigma = median(pairwise_dists) / sqrt(2*log(2)).
If float, use directly as sigma.
n_reference : int, default=500
Number of reference points subsampled from training data.
log_density : bool, default=True
If True, return log(density + 1e-10), else return density directly.
"""
from .gaml.row_geometry import CoordinationDensity
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_ = CoordinationDensity(bandwidth=bandwidth,
n_reference=n_reference,
log_density=log_density)
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 FEBladeSpectrum:
def __init__(self, dataset):
self.dataset = dataset
self.key = "data_fe_blade_spectrum"
self.fitted_ = False
[docs]
def run(self,
features: Union[str, Tuple] = None,
dataset: str = "main",
n_neighbors: int = 10):
"""Generates local blade energy spectrum features from k-NN neighborhood.
For each sample, queries k nearest neighbors in whitened space and computes
grade 1/2/3 blade energies, normalized proportions, spectral slope, and
dominant grade.
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.
n_neighbors : int, default=10
Number of nearest neighbors (k).
"""
from .gaml.row_geometry import BladeSpectrum
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_ = BladeSpectrum(n_neighbors=n_neighbors)
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