Repository: feature-engine/feature_engine
Pull request #512 (2022-08-24 13:24:32)

Refactor creation module


Patch:
diff --git a/feature_engine/_check_input_parameters/__init__.py b/feature_engine/_check_input_parameters/__init__.py
new file mode 100644
index 0000000..e69de29
diff --git a/feature_engine/_check_input_parameters/check_init_input_params.py b/feature_engine/_check_input_parameters/check_init_input_params.py
new file mode 100644
index 0000000..00054da
--- /dev/null
+++ b/feature_engine/_check_input_parameters/check_init_input_params.py
@@ -0,0 +1,15 @@
+
+def _check_param_missing_values(missing_values):
+    if missing_values not in ["raise", "ignore"]:
+        raise ValueError(
+            "missing_values takes only values 'raise' or 'ignore'. "
+            f"Got {missing_values} instead."
+        )
+
+
+def _check_param_drop_original(drop_original):
+    if not isinstance(drop_original, bool):
+        raise TypeError(
+            "drop_original takes only boolean values True and False. "
+            f"Got {drop_original} instead."
+        )
diff --git a/feature_engine/parameter_checks.py b/feature_engine/_check_input_parameters/check_input_dictionary.py
similarity index 69%
rename from feature_engine/parameter_checks.py
rename to feature_engine/_check_input_parameters/check_input_dictionary.py
index 3c4573f..a9a0df9 100644
--- a/feature_engine/parameter_checks.py
+++ b/feature_engine/_check_input_parameters/check_input_dictionary.py
@@ -21,9 +21,13 @@ def _check_numerical_dict(dict_: Optional[dict]) -> Optional[dict]:
 
     if isinstance(dict_, dict):
         if not all([isinstance(x, (float, int)) for x in dict_.values()]):
-            raise ValueError("All values in the dictionary must be integer or float")
+            raise ValueError(
+                "All values in the dictionary must be integer or float. "
+                f"Got {dict_} instead."
+            )
 
     elif dict_ is not None:
-        raise TypeError("The parameter can only take a dictionary or None")
-
+        raise TypeError(
+            f"The parameter can only take a dictionary or None. Got {dict_} instead."
+        )
     return None
diff --git a/feature_engine/_docstrings/methods.py b/feature_engine/_docstrings/methods.py
index 97c99e4..4e214a8 100644
--- a/feature_engine/_docstrings/methods.py
+++ b/feature_engine/_docstrings/methods.py
@@ -41,3 +41,8 @@ _inverse_transform_docstring = """inverse_transform:
 _transform_encoders_docstring = """transform:
         Encode the categories to numbers.
     """.rstrip()
+
+# used in creation module
+_transform_creation_docstring = """transform:
+        Create new features.
+    """.rstrip()
diff --git a/feature_engine/creation/base_creation.py b/feature_engine/creation/base_creation.py
index 3611c1f..3dab2cf 100644
--- a/feature_engine/creation/base_creation.py
+++ b/feature_engine/creation/base_creation.py
@@ -4,6 +4,10 @@ import pandas as pd
 from sklearn.base import BaseEstimator, TransformerMixin
 from sklearn.utils.validation import check_is_fitted
 
+from feature_engine._check_input_parameters.check_init_input_params import (
+    _check_param_drop_original,
+    _check_param_missing_values,
+)
 from feature_engine._variable_handling.variable_type_selection import (
     _find_or_check_numerical_variables,
 )
@@ -19,27 +23,14 @@ from feature_engine.tags import _return_tags
 class BaseCreation(BaseEstimator, TransformerMixin):
     """Shared set-up, checks and methods across creation transformers."""
 
-    _transform_docstring = """transform:
-            Create new features.
-        """.rstrip()
-
     def __init__(
         self,
         missing_values: str = "raise",
         drop_original: bool = False,
     ) -> None:
 
-        if missing_values not in ["raise", "ignore"]:
-            raise ValueError(
-                "missing_values takes only values 'raise' or 'ignore'. "
-                f"Got {missing_values} instead."
-            )
-
-        if not isinstance(drop_original, bool):
-            raise TypeError(
-                "drop_original takes only boolean values True and False. "
-                f"Got {drop_original} instead."
-            )
+        _check_param_missing_values(missing_values)
+        _check_param_drop_original(drop_original)
 
         self.missing_values = missing_values
         self.drop_original = drop_original
diff --git a/feature_engine/creation/cyclical_features.py b/feature_engine/creation/cyclical_features.py
index 1b48bf6..da33d09 100644
--- a/feature_engine/creation/cyclical_features.py
+++ b/feature_engine/creation/cyclical_features.py
@@ -6,6 +6,12 @@ from sklearn.utils.validation import check_is_fitted
 
 from feature_engine._base_transformers.base_numerical import BaseNumericalTransformer
 from feature_engine._base_transformers.mixins import FitFromDictMixin
+from feature_engine._check_input_parameters.check_init_input_params import (
+    _check_param_drop_original,
+)
+from feature_engine._check_input_parameters.check_input_dictionary import (
+    _check_numerical_dict,
+)
 from feature_engine._docstrings.fit_attributes import (
     _feature_names_in_docstring,
     _n_features_in_docstring,
@@ -15,7 +21,10 @@ from feature_engine._docstrings.init_parameters import (
     _drop_original_docstring,
     _variables_numerical_docstring,
 )
-from feature_engine._docstrings.methods import _fit_transform_docstring
+from feature_engine._docstrings.methods import (
+    _fit_transform_docstring,
+    _transform_creation_docstring,
+)
 from feature_engine._docstrings.substitute import Substitution
 from feature_engine._variable_handling.init_parameter_checks import (
     _check_init_parameter_variables,
@@ -29,6 +38,7 @@ from feature_engine._variable_handling.init_parameter_checks import (
     feature_names_in_=_feature_names_in_docstring,
     n_features_in_=_n_features_in_docstring,
     fit_transform=_fit_transform_docstring,
+    transform=_transform_creation_docstring,
 )
 class CyclicalFeatures(BaseNumericalTransformer, FitFromDictMixin):
     """
@@ -77,8 +87,7 @@ class CyclicalFeatures(BaseNumericalTransformer, FitFromDictMixin):
 
     {fit_transform}
 
-    transform:
-        Adds new features.
+    {transform}
 
     References
     ----------
@@ -94,20 +103,8 @@ class CyclicalFeatures(BaseNumericalTransformer, FitFromDictMixin):
         drop_original: Optional[bool] = False,
     ) -> None:
 
-        if max_values:
-            if not isinstance(max_values, dict) or not all(
-                isinstance(var, (int, float)) for var in list(max_values.values())
-            ):
-                raise TypeError(
-                    "max_values takes a dictionary where the values are numerical. "
-                    f"Got {max_values} instead."
-                )
-
-        if not isinstance(drop_original, bool):
-            raise TypeError(
-                "drop_original takes only boolean values True and False. "
-                f"Got {drop_original} instead."
-            )
+        _check_numerical_dict(max_values)
+        _check_param_drop_original(drop_original)
 
         self.variables = _check_init_parameter_variables(variables)
         self.max_values = max_values
diff --git a/feature_engine/creation/math_features.py b/feature_engine/creation/math_features.py
index ce0b750..136b6d4 100644
--- a/feature_engine/creation/math_features.py
+++ b/feature_engine/creation/math_features.py
@@ -14,6 +14,7 @@ from feature_engine._docstrings.init_parameters import (
 from feature_engine._docstrings.methods import (
     _fit_not_learn_docstring,
     _fit_transform_docstring,
+    _transform_creation_docstring,
 )
 from feature_engine._docstrings.substitute import Substitution
 from feature_engine.creation.base_creation import BaseCreation
@@ -25,7 +26,7 @@ from feature_engine.creation.base_creation import BaseCreation
     feature_names_in_=_feature_names_in_docstring,
     n_features_in_=_n_features_in_docstring,
     fit=_fit_not_learn_docstring,
-    transform=BaseCreation._transform_docstring,
+    transform=_transform_creation_docstring,
     fit_transform=_fit_transform_docstring,
 )
 class MathFeatures(BaseCreation):
diff --git a/feature_engine/creation/relative_features.py b/feature_engine/creation/relative_features.py
index 6cd602d..3096e58 100644
--- a/feature_engine/creation/relative_features.py
+++ b/feature_engine/creation/relative_features.py
@@ -15,6 +15,7 @@ from feature_engine._docstrings.init_parameters import (
 from feature_engine._docstrings.methods import (
     _fit_not_learn_docstring,
     _fit_transform_docstring,
+    _transform_creation_docstring,
 )
 from feature_engine._docstrings.substitute import Substitution
 from feature_engine._variable_handling.variable_type_selection import (
@@ -41,7 +42,7 @@ _PERMITTED_FUNCTIONS = [
     feature_names_in_=_feature_names_in_docstring,
     n_features_in_=_n_features_in_docstring,
     fit=_fit_not_learn_docstring,
-    transform=BaseCreation._transform_docstring,
+    transform=_transform_creation_docstring,
     fit_transform=_fit_transform_docstring,
 )
 class RelativeFeatures(BaseCreation):
diff --git a/feature_engine/imputation/arbitrary_number.py b/feature_engine/imputation/arbitrary_number.py
index 0107a44..fa2e56e 100644
--- a/feature_engine/imputation/arbitrary_number.py
+++ b/feature_engine/imputation/arbitrary_number.py
@@ -5,6 +5,9 @@ from typing import List, Optional, Union
 
 import pandas as pd
 
+from feature_engine._check_input_parameters.check_input_dictionary import (
+    _check_numerical_dict,
+)
 from feature_engine._docstrings.fit_attributes import (
     _feature_names_in_docstring,
     _n_features_in_docstring,
@@ -23,7 +26,6 @@ from feature_engine._variable_handling.variable_type_selection import (
 )
 from feature_engine.dataframe_checks import check_X
 from feature_engine.imputation.base_imputer import BaseImputer
-from feature_engine.parameter_checks import _check_numerical_dict
 
 
 @Substitution(
diff --git a/feature_engine/outliers/artbitrary.py b/feature_engine/outliers/artbitrary.py
index 96b0e30..76ff468 100644
--- a/feature_engine/outliers/artbitrary.py
+++ b/feature_engine/outliers/artbitrary.py
@@ -6,6 +6,9 @@ from typing import Optional
 
 import pandas as pd
 
+from feature_engine._check_input_parameters.check_input_dictionary import (
+    _check_numerical_dict,
+)
 from feature_engine._docstrings.fit_attributes import (
     _feature_names_in_docstring,
     _n_features_in_docstring,
@@ -26,7 +29,6 @@ from feature_engine.dataframe_checks import (
     check_X,
 )
 from feature_engine.outliers.base_outlier import BaseOutlier
-from feature_engine.parameter_checks import _check_numerical_dict
 from feature_engine.tags import _return_tags
 
 


Test patch:
diff --git a/tests/test_creation/test_cyclical_features.py b/tests/test_creation/test_cyclical_features.py
index 60343d6..f61204a 100644
--- a/tests/test_creation/test_cyclical_features.py
+++ b/tests/test_creation/test_cyclical_features.py
@@ -158,7 +158,7 @@ def test_raises_error_when_init_parameters_not_permitted(df_cyclical):
         # when max_values is not a dictionary
         CyclicalFeatures(max_values=("dayi", 31))
 
-    with pytest.raises(TypeError):
+    with pytest.raises(ValueError):
         # when max_values values are not integers or string
         CyclicalFeatures(max_values={"day": "31"})
 
diff --git a/tests/test_parameter_checks.py b/tests/test_parameter_checks.py
index e8e878b..49b3065 100644
--- a/tests/test_parameter_checks.py
+++ b/tests/test_parameter_checks.py
@@ -1,6 +1,8 @@
 import pytest
 
-from feature_engine.parameter_checks import _check_numerical_dict
+from feature_engine._check_input_parameters.check_input_dictionary import (
+    _check_numerical_dict,
+)
 
 
 @pytest.mark.parametrize("input_dict", [{"a": 1, "b": "c"}, {1: 1, 2: "c"}])