Source code for modeva.data.feature_engineering.row_geometry

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 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", 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 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", 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