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 FERFProximity:
def __init__(self, dataset):
self.dataset = dataset
self.key = "data_fe_rf_proximity"
self.fitted_ = False
[docs]
def run(self,
features: Union[str, Tuple] = None,
dataset: str = "main",
n_estimators: int = 100,
max_depth: int = 6,
n_landmarks: int = 50):
"""Generates RF leaf co-occurrence proximity features via Nystrom approximation.
Trains a random forest and uses its leaf co-occurrence as a similarity kernel.
The Nystrom method computes a fixed-width feature map from landmark points.
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.
n_estimators : int, default=100
Number of trees in the forest.
max_depth : int, default=6
Maximum tree depth.
n_landmarks : int, default=50
Number of Nystrom anchor points.
"""
from .gaml.tree_ops import RFProximityTransformer
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)
# Get target for supervised fitting
y_idx = self.dataset.target_feature_index
y = data[:, y_idx].astype(np.float64).ravel()
self.gaml_transformer_ = RFProximityTransformer(n_estimators=n_estimators,
max_depth=max_depth,
n_landmarks=n_landmarks)
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
[docs]
class FESpectralProximity:
def __init__(self, dataset):
self.dataset = dataset
self.key = "data_fe_spectral_proximity"
self.fitted_ = False
[docs]
def run(self,
features: Union[str, Tuple] = None,
dataset: str = "main",
n_estimators: int = 100,
max_depth: int = 6,
n_components: int = 10):
"""Generates spectral embedding features from RF proximity kernel.
Builds the RF proximity matrix, computes the normalized graph Laplacian, and
extracts the smoothest eigenvectors as features. Uses Nystrom extension at
transform time. 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.
n_estimators : int, default=100
Number of trees in the forest.
max_depth : int, default=6
Maximum tree depth.
n_components : int, default=10
Number of spectral components.
"""
from .gaml.tree_ops import SpectralProximityTransformer
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)
# Get target for supervised fitting
y_idx = self.dataset.target_feature_index
y = data[:, y_idx].astype(np.float64).ravel()
self.gaml_transformer_ = SpectralProximityTransformer(n_estimators=n_estimators,
max_depth=max_depth,
n_components=n_components)
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
[docs]
class FEDirectRS:
def __init__(self, dataset):
self.dataset = dataset
self.key = "data_fe_direct_rs"
self.fitted_ = False
[docs]
def run(self,
features: Union[str, Tuple] = None,
dataset: str = "main",
n_estimators: int = 50,
max_depth: int = 4,
regularization: float = 1e-8):
"""Generates DirectRS stretch features from random forest leaf geometry.
Builds a weighted outer-product matrix from per-leaf centroids and variances,
decomposes via eigendecomposition, and applies the resulting stretch matrix.
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.
n_estimators : int, default=50
Number of trees in the forest.
max_depth : int, default=4
Maximum tree depth.
regularization : float, default=1e-8
Regularization added to diagonal of G before eigendecomposition.
"""
from .gaml.tree_ops import DirectRSTransformer
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)
# Get target for supervised fitting
y_idx = self.dataset.target_feature_index
y = data[:, y_idx].astype(np.float64).ravel()
self.gaml_transformer_ = DirectRSTransformer(n_estimators=n_estimators,
max_depth=max_depth,
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