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 FEBivector:
def __init__(self, dataset):
self.dataset = dataset
self.key = "data_fe_bivector"
self.fitted_ = False
[docs]
def run(self,
features: Union[str, Tuple] = None,
dataset: str = "main",
max_features: int = 300,
selection: str = "variance"):
"""Generates grade-2 bivector features (pairwise feature products).
For each pair (i, j) with i < j, computes B_ij = X_i * X_j.
This captures pairwise nonlinear interactions based on Geometric Algebra wedge products.
Parameters
----------
features : str or tuple, default=None
Features to use for bivector computation. If None, all numerical features are used.
dataset : {"main", "train", "test"}, default="main"
Dataset used to fit the transformer.
max_features : int, default=300
Maximum number of bivector features to generate.
selection : {"all", "random", "variance"}, default="variance"
How to select pairs if max_features < C(n,2):
- "all": use all pairs (ignore max_features)
- "random": random selection
- "variance": highest variance pairs
"""
from .gaml.bivector import BivectorFeatures
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_ = BivectorFeatures(max_features=max_features, selection=selection)
self.gaml_transformer_.fit(X)
gaml_names = self.gaml_transformer_.get_feature_names(input_features=features)
self.feature_names_out_ = [f"bv_{name}" for name in gaml_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 FEWedgeBivector:
def __init__(self, dataset):
self.dataset = dataset
self.key = "data_fe_wedge_bivector"
self.fitted_ = False
[docs]
def run(self,
features: Union[str, Tuple] = None,
dataset: str = "main",
max_features: int = 300,
selection: str = "variance"):
"""Generates wedge-weighted pairwise feature products.
Suppresses nearly-collinear pairs and amplifies orthogonal ones by weighting
each product X_i * X_j by the column-level sin(angle) between features i and j.
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_features : int, default=300
Maximum number of pairs to generate.
selection : {"variance", "random"}, default="variance"
Pair selection method if max_features < C(d,2).
"""
from .gaml.bivector import WedgeBivector
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_ = WedgeBivector(max_features=max_features, selection=selection)
self.gaml_transformer_.fit(X)
gaml_names = self.gaml_transformer_.get_feature_names(input_features=features)
self.feature_names_out_ = [f"wbv_{name}" for name in gaml_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