Source code for etna.transforms.base

from abc import ABC
from abc import abstractmethod
from copy import deepcopy

import pandas as pd

from etna.core import BaseMixin


[docs]class FutureMixin: """Mixin for transforms that can convert non-regressor column to a regressor one."""
[docs]class Transform(ABC, BaseMixin): """Base class to create any transforms to apply to data."""
[docs] @abstractmethod def fit(self, df: pd.DataFrame) -> "Transform": """Fit feature model. Should be implemented by user. Parameters ---------- df Returns ------- : """ pass
[docs] @abstractmethod def transform(self, df: pd.DataFrame) -> pd.DataFrame: """Transform dataframe. Should be implemented by user Parameters ---------- df Returns ------- : """ pass
[docs] def fit_transform(self, df: pd.DataFrame) -> pd.DataFrame: """ May be reimplemented. But it is not recommended. Parameters ---------- df Returns ------- : """ return self.fit(df).transform(df)
[docs] def inverse_transform(self, df: pd.DataFrame) -> pd.DataFrame: """Inverse transforms dataframe. Parameters ---------- df Returns ------- : """ return df
[docs]class PerSegmentWrapper(Transform): """Class to apply transform in per segment manner.""" def __init__(self, transform): self._base_transform = transform self.segment_transforms = {} self.segments = None
[docs] def fit(self, df: pd.DataFrame) -> "PerSegmentWrapper": """Fit transform on each segment.""" self.segments = df.columns.get_level_values(0).unique() for segment in self.segments: self.segment_transforms[segment] = deepcopy(self._base_transform) self.segment_transforms[segment].fit(df[segment]) return self
[docs] def transform(self, df: pd.DataFrame) -> pd.DataFrame: """Apply transform to each segment separately.""" results = [] for key, value in self.segment_transforms.items(): seg_df = value.transform(df[key]) _idx = seg_df.columns.to_frame() _idx.insert(0, "segment", key) seg_df.columns = pd.MultiIndex.from_frame(_idx) results.append(seg_df) df = pd.concat(results, axis=1) df = df.sort_index(axis=1) df.columns.names = ["segment", "feature"] return df
[docs] def inverse_transform(self, df: pd.DataFrame) -> pd.DataFrame: """Apply inverse_transform to each segment.""" results = [] for key, value in self.segment_transforms.items(): seg_df = value.inverse_transform(df[key]) _idx = seg_df.columns.to_frame() _idx.insert(0, "segment", key) seg_df.columns = pd.MultiIndex.from_frame(_idx) results.append(seg_df) df = pd.concat(results, axis=1) df = df.sort_index(axis=1) df.columns.names = ["segment", "feature"] return df