diff --git a/feature_engine/_check_input_parameters/__init__.py b/feature_engine/_check_input_parameters/__init__.py new file mode 100644 index 000000000..e69de29bb 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 000000000..00054da2c --- /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 3c4573f8b..a9a0df9d8 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 97c99e409..4e214a8d6 100644 --- a/feature_engine/_docstrings/methods.py +++ b/feature_engine/_docstrings/methods.py @@ -41,3 +41,8 @@ _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 3611c1fc6..3dab2cf16 100644 --- a/feature_engine/creation/base_creation.py +++ b/feature_engine/creation/base_creation.py @@ -4,6 +4,10 @@ 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 @@ 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 1b48bf6a7..da33d0996 100644 --- a/feature_engine/creation/cyclical_features.py +++ b/feature_engine/creation/cyclical_features.py @@ -6,6 +6,12 @@ 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 @@ _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 @@ 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 @@ def __init__( 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 ce0b750a1..136b6d468 100644 --- a/feature_engine/creation/math_features.py +++ b/feature_engine/creation/math_features.py @@ -14,6 +14,7 @@ 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 @@ 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 6cd602db9..3096e5875 100644 --- a/feature_engine/creation/relative_features.py +++ b/feature_engine/creation/relative_features.py @@ -15,6 +15,7 @@ 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 @@ 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 0107a4414..fa2e56e1b 100644 --- a/feature_engine/imputation/arbitrary_number.py +++ b/feature_engine/imputation/arbitrary_number.py @@ -5,6 +5,9 @@ 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.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 96b0e303c..76ff468a2 100644 --- a/feature_engine/outliers/artbitrary.py +++ b/feature_engine/outliers/artbitrary.py @@ -6,6 +6,9 @@ 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 @@ 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 diff --git a/tests/test_creation/test_cyclical_features.py b/tests/test_creation/test_cyclical_features.py index 60343d644..f61204a59 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 e8e878b75..49b306586 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"}])