multiplication
Multiplication
Bases: NToOneTransformer
N-to-1 transformation allowing to get 1 variable by applying a multiplication of N other variables.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
powers | List[float] | Powers applied to each variable concerned by the multiplicative transformation. | required |
ignore_input_indexes | Optional[List[int]] | Indexes of the data in series to ignore when computing the repartition. | None |
Source code in eki_mmo_equations/n_to_one_transformations/multiplication.py
class Multiplication(NToOneTransformer):
"""N-to-1 transformation allowing to get 1 variable by applying a multiplication of N other variables.
```math
serie_1^{(\\alpha_1)} \\times serie_2^{(\\alpha_2)} \\times ... \\times serie_N^{(\\alpha_N)}
```
Args:
powers (List[float]): Powers applied to each variable concerned by the multiplicative transformation.
ignore_input_indexes (Optional[List[int]], optional): Indexes of the data in series to ignore when
computing the repartition.
"""
def __init__(self, powers: List[float], ignore_input_indexes: Optional[List[int]] = None):
self.powers: List[float] = powers
self.ignore_input_indexes: List[int] = ignore_input_indexes if ignore_input_indexes else []
@property
def parameters(self) -> Dict[str, float]:
return self.__dict__
# ------- METHODS -------
def transform(self, series: List[np.ndarray], copy=False) -> np.ndarray:
series = super().transform(series, copy)
return self._transformer(series, self.powers)
def repartition(self, series: List[np.ndarray]) -> List[np.ndarray]:
"Returns an estimated repartition of the output series from the initial input series."
repartition_series = [serie for i, serie in enumerate(series) if i not in self.ignore_input_indexes]
repartition_powers = [power for i, power in enumerate(self.powers) if i not in self.ignore_input_indexes]
powered_series = [serie**power for serie, power in zip(repartition_series, repartition_powers)]
with np.errstate(divide="ignore", invalid="ignore"):
weighted_series = powered_series / reduce(lambda a, b: a * b, powered_series)
proportionned_weighted_series = [
np.nan_to_num(weighted_serie / np.sum(weighted_series, axis=0)) for weighted_serie in weighted_series
]
for index in self.ignore_input_indexes:
proportionned_weighted_series.insert(index, np.zeros(len(series[index])))
return proportionned_weighted_series
# ------- TRANSFORMERS -------
@staticmethod
def _transformer(series: List[np.ndarray], powers: List[float]) -> np.ndarray:
"Returns the multiplication of the different input variables."
transformed_series = [serie**power for serie, power in zip(series, powers)]
return reduce(lambda a, b: a * b, transformed_series)
# ------- CHECKERS -------
def check_params(self, series: List[np.ndarray]):
"""Check if parameters respect their application scope."""
if not len(self.powers) == len(series):
raise ParameterScopeException(
"Number of series don't match number of powers"
+ f"Number of powers:{len(self.powers)} . Number of series:{len(series)}"
)
if len(self.ignore_input_indexes) != len(set(self.ignore_input_indexes)):
raise ParameterScopeException(
f"Incorrect {self.__class__.__name__} parameters. Values ignore_input_indexes"
f" should be unique. Current values:{self.ignore_input_indexes}"
)
if not all(index < len(series) for index in self.ignore_input_indexes):
raise ParameterScopeException(
f"Incorrect {self.__class__.__name__} parameters. Each value of ignore_input_indexes"
f" should be lower than the number of series as input - lower than {len(series)}."
)
if len(self.ignore_input_indexes) >= len(series):
raise ParameterScopeException(
f"Incorrect {self.__class__.__name__}. Length of ignore_input_indexes"
f" should be inferior to length of input series - lower than {len(series)}."
)
check_params(series)
Check if parameters respect their application scope.
Source code in eki_mmo_equations/n_to_one_transformations/multiplication.py
def check_params(self, series: List[np.ndarray]):
"""Check if parameters respect their application scope."""
if not len(self.powers) == len(series):
raise ParameterScopeException(
"Number of series don't match number of powers"
+ f"Number of powers:{len(self.powers)} . Number of series:{len(series)}"
)
if len(self.ignore_input_indexes) != len(set(self.ignore_input_indexes)):
raise ParameterScopeException(
f"Incorrect {self.__class__.__name__} parameters. Values ignore_input_indexes"
f" should be unique. Current values:{self.ignore_input_indexes}"
)
if not all(index < len(series) for index in self.ignore_input_indexes):
raise ParameterScopeException(
f"Incorrect {self.__class__.__name__} parameters. Each value of ignore_input_indexes"
f" should be lower than the number of series as input - lower than {len(series)}."
)
if len(self.ignore_input_indexes) >= len(series):
raise ParameterScopeException(
f"Incorrect {self.__class__.__name__}. Length of ignore_input_indexes"
f" should be inferior to length of input series - lower than {len(series)}."
)
repartition(series)
Returns an estimated repartition of the output series from the initial input series.
Source code in eki_mmo_equations/n_to_one_transformations/multiplication.py
def repartition(self, series: List[np.ndarray]) -> List[np.ndarray]:
"Returns an estimated repartition of the output series from the initial input series."
repartition_series = [serie for i, serie in enumerate(series) if i not in self.ignore_input_indexes]
repartition_powers = [power for i, power in enumerate(self.powers) if i not in self.ignore_input_indexes]
powered_series = [serie**power for serie, power in zip(repartition_series, repartition_powers)]
with np.errstate(divide="ignore", invalid="ignore"):
weighted_series = powered_series / reduce(lambda a, b: a * b, powered_series)
proportionned_weighted_series = [
np.nan_to_num(weighted_serie / np.sum(weighted_series, axis=0)) for weighted_serie in weighted_series
]
for index in self.ignore_input_indexes:
proportionned_weighted_series.insert(index, np.zeros(len(series[index])))
return proportionned_weighted_series