From 025c757348b41e0a2e925fa5ce6f51b76ceece56 Mon Sep 17 00:00:00 2001 From: Soledad Galli Date: Sun, 10 Dec 2023 12:28:31 +0100 Subject: [PATCH] reduce cognitive load for testing input values to variables --- .../__init__.py | 0 .../check_init_input_params.py | 0 .../check_input_dictionary.py | 0 .../_check_init_parameters/check_variables.py | 39 ++++++++++++++++ feature_engine/_prediction/base_predictor.py | 6 +-- feature_engine/creation/base_creation.py | 2 +- feature_engine/creation/cyclical_features.py | 12 ++--- feature_engine/datetime/datetime.py | 6 +-- .../datetime/datetime_subtraction.py | 8 ++-- .../discretisation/decision_tree.py | 6 +-- .../discretisation/equal_frequency.py | 6 +-- feature_engine/discretisation/equal_width.py | 6 +-- .../discretisation/geometric_width.py | 8 ++-- feature_engine/encoding/base_encoder.py | 8 ++-- feature_engine/imputation/arbitrary_number.py | 8 ++-- feature_engine/imputation/categorical.py | 6 +-- .../imputation/drop_missing_data.py | 6 +-- feature_engine/imputation/end_tail.py | 6 +-- feature_engine/imputation/mean_median.py | 6 +-- .../imputation/missing_indicator.py | 6 +-- feature_engine/imputation/random_sample.py | 8 ++-- feature_engine/outliers/artbitrary.py | 2 +- feature_engine/outliers/base_outlier.py | 6 +-- .../selection/base_recursive_selector.py | 6 +-- .../selection/drop_constant_features.py | 6 +-- .../selection/drop_correlated_features.py | 6 +-- .../selection/drop_duplicate_features.py | 6 +-- feature_engine/selection/drop_psi_features.py | 6 +-- feature_engine/selection/information_value.py | 6 +-- feature_engine/selection/shuffle_features.py | 6 +-- .../selection/single_feature_performance.py | 6 +-- .../selection/smart_correlation_selection.py | 6 +-- .../selection/target_mean_selection.py | 6 +-- .../forecasting/base_forecast_transformers.py | 6 +-- feature_engine/transformation/arcsin.py | 6 +-- feature_engine/transformation/boxcox.py | 6 +-- feature_engine/transformation/log.py | 8 ++-- feature_engine/transformation/power.py | 6 +-- feature_engine/transformation/reciprocal.py | 6 +-- feature_engine/transformation/yeojohnson.py | 6 +-- .../_init_parameter_checks.py | 34 -------------- feature_engine/wrappers/wrappers.py | 6 +-- .../test_check_init_input_params.py | 2 +- .../test_check_input_dictionary.py | 2 +- .../test_check_variables.py | 45 +++++++++++++++++++ .../test_init_parameter_checks.py | 31 ------------- 46 files changed, 202 insertions(+), 183 deletions(-) rename feature_engine/{_check_input_parameters => _check_init_parameters}/__init__.py (100%) rename feature_engine/{_check_input_parameters => _check_init_parameters}/check_init_input_params.py (100%) rename feature_engine/{_check_input_parameters => _check_init_parameters}/check_input_dictionary.py (100%) create mode 100644 feature_engine/_check_init_parameters/check_variables.py delete mode 100644 feature_engine/variable_handling/_init_parameter_checks.py create mode 100644 tests/test_check_input_parameters/test_check_variables.py delete mode 100644 tests/test_variable_handling/test_init_parameter_checks.py diff --git a/feature_engine/_check_input_parameters/__init__.py b/feature_engine/_check_init_parameters/__init__.py similarity index 100% rename from feature_engine/_check_input_parameters/__init__.py rename to feature_engine/_check_init_parameters/__init__.py diff --git a/feature_engine/_check_input_parameters/check_init_input_params.py b/feature_engine/_check_init_parameters/check_init_input_params.py similarity index 100% rename from feature_engine/_check_input_parameters/check_init_input_params.py rename to feature_engine/_check_init_parameters/check_init_input_params.py diff --git a/feature_engine/_check_input_parameters/check_input_dictionary.py b/feature_engine/_check_init_parameters/check_input_dictionary.py similarity index 100% rename from feature_engine/_check_input_parameters/check_input_dictionary.py rename to feature_engine/_check_init_parameters/check_input_dictionary.py diff --git a/feature_engine/_check_init_parameters/check_variables.py b/feature_engine/_check_init_parameters/check_variables.py new file mode 100644 index 000000000..cc3073783 --- /dev/null +++ b/feature_engine/_check_init_parameters/check_variables.py @@ -0,0 +1,39 @@ +from typing import Any, List, Union + +Variables = Union[None, int, str, List[Union[str, int]]] + + +def _check_variables_input_value(variables: Variables) -> Any: + """ + Checks that the input value for the `variables` parameter located in the init of + all Feature-engine transformers is of the correct type. + Allowed values are None, int, str or list of strings and integers. + + Parameters + ---------- + variables : string, int, list of strings, list of integers. Default=None + + Returns + ------- + variables: same as input + """ + + msg = ( + "`variables` should contain a string, an integer or a list of strings or " + f"integers. Got {variables} instead." + ) + msg_dupes = "The list entered in `variables` contains duplicated variable names." + msg_empty = "The list of `variables` is empty." + + if variables is not None: + if isinstance(variables, list): + if not all(isinstance(i, (str, int)) for i in variables): + raise ValueError(msg) + if len(variables) == 0: + raise ValueError(msg_empty) + if len(variables) != len(set(variables)): + raise ValueError(msg_dupes) + else: + if not isinstance(variables, (str, int)): + raise ValueError(msg) + return variables diff --git a/feature_engine/_prediction/base_predictor.py b/feature_engine/_prediction/base_predictor.py index 611fcdc29..19860696f 100644 --- a/feature_engine/_prediction/base_predictor.py +++ b/feature_engine/_prediction/base_predictor.py @@ -19,8 +19,8 @@ ) from feature_engine.encoding import MeanEncoder from feature_engine.tags import _return_tags -from feature_engine.variable_handling._init_parameter_checks import ( - _check_init_parameter_variables, +from feature_engine._check_init_parameters.check_variables import ( + _check_variables_input_value, ) from feature_engine.variable_handling.variable_type_selection import ( find_categorical_and_numerical_variables, @@ -98,7 +98,7 @@ def __init__( f"Got {strategy} instead." ) - self.variables = _check_init_parameter_variables(variables) + self.variables = _check_variables_input_value(variables) self.bins = bins self.strategy = strategy diff --git a/feature_engine/creation/base_creation.py b/feature_engine/creation/base_creation.py index 4554830c3..2862a7f65 100644 --- a/feature_engine/creation/base_creation.py +++ b/feature_engine/creation/base_creation.py @@ -5,7 +5,7 @@ from sklearn.utils.validation import check_is_fitted from feature_engine._base_transformers.mixins import GetFeatureNamesOutMixin -from feature_engine._check_input_parameters.check_init_input_params import ( +from feature_engine._check_init_parameters.check_init_input_params import ( _check_param_drop_original, _check_param_missing_values, ) diff --git a/feature_engine/creation/cyclical_features.py b/feature_engine/creation/cyclical_features.py index 3f804818d..a00a41b6a 100644 --- a/feature_engine/creation/cyclical_features.py +++ b/feature_engine/creation/cyclical_features.py @@ -8,10 +8,13 @@ FitFromDictMixin, GetFeatureNamesOutMixin, ) -from feature_engine._check_input_parameters.check_init_input_params import ( +from feature_engine._check_init_parameters.check_init_input_params import ( _check_param_drop_original, ) -from feature_engine._check_input_parameters.check_input_dictionary import ( +from feature_engine._check_init_parameters.check_variables import ( + _check_variables_input_value, +) +from feature_engine._check_init_parameters.check_input_dictionary import ( _check_numerical_dict, ) from feature_engine._docstrings.fit_attributes import ( @@ -28,9 +31,6 @@ _transform_creation_docstring, ) from feature_engine._docstrings.substitute import Substitution -from feature_engine.variable_handling._init_parameter_checks import ( - _check_init_parameter_variables, -) @Substitution( @@ -129,7 +129,7 @@ def __init__( _check_numerical_dict(max_values) _check_param_drop_original(drop_original) - self.variables = _check_init_parameter_variables(variables) + self.variables = _check_variables_input_value(variables) self.max_values = max_values self.drop_original = drop_original diff --git a/feature_engine/datetime/datetime.py b/feature_engine/datetime/datetime.py index a9eb64499..3fc93fdc4 100644 --- a/feature_engine/datetime/datetime.py +++ b/feature_engine/datetime/datetime.py @@ -29,8 +29,8 @@ FEATURES_SUFFIXES, FEATURES_SUPPORTED, ) -from feature_engine.variable_handling._init_parameter_checks import ( - _check_init_parameter_variables, +from feature_engine._check_init_parameters.check_variables import ( + _check_variables_input_value, ) from feature_engine.variable_handling._variable_type_checks import ( _is_categorical_and_is_datetime, @@ -219,7 +219,7 @@ def __init__( if utc is not None and not isinstance(utc, bool): raise ValueError("utc takes only booleans or None. " f"Got {utc} instead.") - self.variables = _check_init_parameter_variables(variables) + self.variables = _check_variables_input_value(variables) self.drop_original = drop_original self.missing_values = missing_values self.dayfirst = dayfirst diff --git a/feature_engine/datetime/datetime_subtraction.py b/feature_engine/datetime/datetime_subtraction.py index 90b9db7d8..f2a0b1654 100644 --- a/feature_engine/datetime/datetime_subtraction.py +++ b/feature_engine/datetime/datetime_subtraction.py @@ -25,8 +25,8 @@ check_X, ) from feature_engine.variable_handling import find_or_check_datetime_variables -from feature_engine.variable_handling._init_parameter_checks import ( - _check_init_parameter_variables, +from feature_engine._check_init_parameters.check_variables import ( + _check_variables_input_value, ) _example = """ @@ -198,8 +198,8 @@ def __init__( ) super().__init__(missing_values, drop_original) - self.variables = _check_init_parameter_variables(variables) - self.reference = _check_init_parameter_variables(reference) + self.variables = _check_variables_input_value(variables) + self.reference = _check_variables_input_value(reference) self.new_variables_names = new_variables_names self.output_unit = output_unit self.dayfirst = dayfirst diff --git a/feature_engine/discretisation/decision_tree.py b/feature_engine/discretisation/decision_tree.py index cb5eab097..a417f3a86 100644 --- a/feature_engine/discretisation/decision_tree.py +++ b/feature_engine/discretisation/decision_tree.py @@ -20,8 +20,8 @@ from feature_engine._docstrings.methods import _fit_transform_docstring from feature_engine._docstrings.substitute import Substitution from feature_engine.tags import _return_tags -from feature_engine.variable_handling._init_parameter_checks import ( - _check_init_parameter_variables, +from feature_engine._check_init_parameters.check_variables import ( + _check_variables_input_value, ) @@ -172,7 +172,7 @@ def __init__( self.cv = cv self.scoring = scoring self.regression = regression - self.variables = _check_init_parameter_variables(variables) + self.variables = _check_variables_input_value(variables) self.param_grid = param_grid self.random_state = random_state diff --git a/feature_engine/discretisation/equal_frequency.py b/feature_engine/discretisation/equal_frequency.py index 86d523061..54e7d362d 100644 --- a/feature_engine/discretisation/equal_frequency.py +++ b/feature_engine/discretisation/equal_frequency.py @@ -26,8 +26,8 @@ ) from feature_engine._docstrings.substitute import Substitution from feature_engine.discretisation.base_discretiser import BaseDiscretiser -from feature_engine.variable_handling._init_parameter_checks import ( - _check_init_parameter_variables, +from feature_engine._check_init_parameters.check_variables import ( + _check_variables_input_value, ) @@ -143,7 +143,7 @@ def __init__( super().__init__(return_object, return_boundaries, precision) self.q = q - self.variables = _check_init_parameter_variables(variables) + self.variables = _check_variables_input_value(variables) def fit(self, X: pd.DataFrame, y: Optional[pd.Series] = None): """ diff --git a/feature_engine/discretisation/equal_width.py b/feature_engine/discretisation/equal_width.py index 3a46b6336..07a348148 100644 --- a/feature_engine/discretisation/equal_width.py +++ b/feature_engine/discretisation/equal_width.py @@ -26,8 +26,8 @@ ) from feature_engine._docstrings.substitute import Substitution from feature_engine.discretisation.base_discretiser import BaseDiscretiser -from feature_engine.variable_handling._init_parameter_checks import ( - _check_init_parameter_variables, +from feature_engine._check_init_parameters.check_variables import ( + _check_variables_input_value, ) @@ -151,7 +151,7 @@ def __init__( super().__init__(return_object, return_boundaries, precision) self.bins = bins - self.variables = _check_init_parameter_variables(variables) + self.variables = _check_variables_input_value(variables) def fit(self, X: pd.DataFrame, y: Optional[pd.Series] = None): """ diff --git a/feature_engine/discretisation/geometric_width.py b/feature_engine/discretisation/geometric_width.py index 5947de812..0e015dd01 100644 --- a/feature_engine/discretisation/geometric_width.py +++ b/feature_engine/discretisation/geometric_width.py @@ -23,8 +23,8 @@ _transform_discretiser_docstring, ) from feature_engine._docstrings.substitute import Substitution -from feature_engine.variable_handling._init_parameter_checks import ( - _check_init_parameter_variables, +from feature_engine._check_init_parameters.check_variables import ( + _check_variables_input_value, ) from feature_engine.discretisation.base_discretiser import BaseDiscretiser @@ -42,7 +42,7 @@ n_features_in_=_n_features_in_docstring, fit_transform=_fit_transform_docstring, power="{1/n}", - subindex="{i+1}" + subindex="{i+1}", ) class GeometricWidthDiscretiser(BaseDiscretiser): """ @@ -142,7 +142,7 @@ def __init__( super().__init__(return_object, return_boundaries, precision) self.bins = bins - self.variables = _check_init_parameter_variables(variables) + self.variables = _check_variables_input_value(variables) def fit(self, X: pd.DataFrame, y: Optional[pd.Series] = None): """ diff --git a/feature_engine/encoding/base_encoder.py b/feature_engine/encoding/base_encoder.py index 3fb773b26..3d220b656 100644 --- a/feature_engine/encoding/base_encoder.py +++ b/feature_engine/encoding/base_encoder.py @@ -18,8 +18,8 @@ check_X, ) from feature_engine.tags import _return_tags -from feature_engine.variable_handling._init_parameter_checks import ( - _check_init_parameter_variables, +from feature_engine._check_init_parameters.check_variables import ( + _check_variables_input_value, ) from feature_engine.variable_handling.variable_type_selection import ( find_all_variables, @@ -54,7 +54,7 @@ def __init__( f"Got {ignore_format} instead." ) - self.variables = _check_init_parameter_variables(variables) + self.variables = _check_variables_input_value(variables) self.ignore_format = ignore_format @@ -95,7 +95,7 @@ def __init__( f"Got {ignore_format} instead." ) - self.variables = _check_init_parameter_variables(variables) + self.variables = _check_variables_input_value(variables) self.ignore_format = ignore_format self.missing_values = missing_values diff --git a/feature_engine/imputation/arbitrary_number.py b/feature_engine/imputation/arbitrary_number.py index d2fea18df..f98f398bc 100644 --- a/feature_engine/imputation/arbitrary_number.py +++ b/feature_engine/imputation/arbitrary_number.py @@ -5,7 +5,7 @@ import pandas as pd -from feature_engine._check_input_parameters.check_input_dictionary import ( +from feature_engine._check_init_parameters.check_input_dictionary import ( _check_numerical_dict, ) from feature_engine._docstrings.fit_attributes import ( @@ -22,8 +22,8 @@ from feature_engine._docstrings.substitute import Substitution from feature_engine.dataframe_checks import check_X from feature_engine.imputation.base_imputer import BaseImputer -from feature_engine.variable_handling._init_parameter_checks import ( - _check_init_parameter_variables, +from feature_engine._check_init_parameters.check_variables import ( + _check_variables_input_value, ) from feature_engine.variable_handling.variable_type_selection import ( find_or_check_numerical_variables, @@ -125,7 +125,7 @@ def __init__( _check_numerical_dict(imputer_dict) - self.variables = _check_init_parameter_variables(variables) + self.variables = _check_variables_input_value(variables) self.imputer_dict = imputer_dict diff --git a/feature_engine/imputation/categorical.py b/feature_engine/imputation/categorical.py index 45a723a86..a8d317222 100644 --- a/feature_engine/imputation/categorical.py +++ b/feature_engine/imputation/categorical.py @@ -19,8 +19,8 @@ from feature_engine.dataframe_checks import check_X from feature_engine.imputation.base_imputer import BaseImputer from feature_engine.tags import _return_tags -from feature_engine.variable_handling._init_parameter_checks import ( - _check_init_parameter_variables, +from feature_engine._check_init_parameters.check_variables import ( + _check_variables_input_value, ) from feature_engine.variable_handling.variable_type_selection import ( find_all_variables, @@ -144,7 +144,7 @@ def __init__( self.imputation_method = imputation_method self.fill_value = fill_value - self.variables = _check_init_parameter_variables(variables) + self.variables = _check_variables_input_value(variables) self.return_object = return_object self.ignore_format = ignore_format diff --git a/feature_engine/imputation/drop_missing_data.py b/feature_engine/imputation/drop_missing_data.py index c6af28366..f0d0f4a84 100644 --- a/feature_engine/imputation/drop_missing_data.py +++ b/feature_engine/imputation/drop_missing_data.py @@ -14,8 +14,8 @@ from feature_engine.dataframe_checks import check_X from feature_engine.imputation.base_imputer import BaseImputer from feature_engine.tags import _return_tags -from feature_engine.variable_handling._init_parameter_checks import ( - _check_init_parameter_variables, +from feature_engine._check_init_parameters.check_variables import ( + _check_variables_input_value, ) from feature_engine.variable_handling.variable_type_selection import find_all_variables @@ -122,7 +122,7 @@ def __init__( f"Got {threshold} instead." ) - self.variables = _check_init_parameter_variables(variables) + self.variables = _check_variables_input_value(variables) self.missing_only = missing_only self.threshold = threshold diff --git a/feature_engine/imputation/end_tail.py b/feature_engine/imputation/end_tail.py index a8fa92736..4e6292b91 100644 --- a/feature_engine/imputation/end_tail.py +++ b/feature_engine/imputation/end_tail.py @@ -21,8 +21,8 @@ from feature_engine._docstrings.substitute import Substitution from feature_engine.dataframe_checks import check_X from feature_engine.imputation.base_imputer import BaseImputer -from feature_engine.variable_handling._init_parameter_checks import ( - _check_init_parameter_variables, +from feature_engine._check_init_parameters.check_variables import ( + _check_variables_input_value, ) from feature_engine.variable_handling.variable_type_selection import ( find_or_check_numerical_variables, @@ -157,7 +157,7 @@ def __init__( self.imputation_method = imputation_method self.tail = tail self.fold = fold - self.variables = _check_init_parameter_variables(variables) + self.variables = _check_variables_input_value(variables) def fit(self, X: pd.DataFrame, y: Optional[pd.Series] = None): """ diff --git a/feature_engine/imputation/mean_median.py b/feature_engine/imputation/mean_median.py index 36d6cac4e..c11b38475 100644 --- a/feature_engine/imputation/mean_median.py +++ b/feature_engine/imputation/mean_median.py @@ -21,8 +21,8 @@ from feature_engine._docstrings.substitute import Substitution from feature_engine.dataframe_checks import check_X from feature_engine.imputation.base_imputer import BaseImputer -from feature_engine.variable_handling._init_parameter_checks import ( - _check_init_parameter_variables, +from feature_engine._check_init_parameters.check_variables import ( + _check_variables_input_value, ) from feature_engine.variable_handling.variable_type_selection import ( find_or_check_numerical_variables, @@ -106,7 +106,7 @@ def __init__( raise ValueError("imputation_method takes only values 'median' or 'mean'") self.imputation_method = imputation_method - self.variables = _check_init_parameter_variables(variables) + self.variables = _check_variables_input_value(variables) def fit(self, X: pd.DataFrame, y: Optional[pd.Series] = None): """ diff --git a/feature_engine/imputation/missing_indicator.py b/feature_engine/imputation/missing_indicator.py index 2cc090677..9a31dcfdd 100644 --- a/feature_engine/imputation/missing_indicator.py +++ b/feature_engine/imputation/missing_indicator.py @@ -14,8 +14,8 @@ from feature_engine.dataframe_checks import check_X from feature_engine.imputation.base_imputer import BaseImputer from feature_engine.tags import _return_tags -from feature_engine.variable_handling._init_parameter_checks import ( - _check_init_parameter_variables, +from feature_engine._check_init_parameters.check_variables import ( + _check_variables_input_value, ) from feature_engine.variable_handling.variable_type_selection import find_all_variables @@ -108,7 +108,7 @@ def __init__( if not isinstance(missing_only, bool): raise ValueError("missing_only takes values True or False") - self.variables = _check_init_parameter_variables(variables) + self.variables = _check_variables_input_value(variables) self.missing_only = missing_only def fit(self, X: pd.DataFrame, y: Optional[pd.Series] = None): diff --git a/feature_engine/imputation/random_sample.py b/feature_engine/imputation/random_sample.py index 40e3f6f71..5073f5fb0 100644 --- a/feature_engine/imputation/random_sample.py +++ b/feature_engine/imputation/random_sample.py @@ -19,8 +19,8 @@ from feature_engine.dataframe_checks import check_X from feature_engine.imputation.base_imputer import BaseImputer from feature_engine.tags import _return_tags -from feature_engine.variable_handling._init_parameter_checks import ( - _check_init_parameter_variables, +from feature_engine._check_init_parameters.check_variables import ( + _check_variables_input_value, ) from feature_engine.variable_handling.variable_type_selection import find_all_variables @@ -158,7 +158,7 @@ def __init__( "or more variables which will be used to seed the imputer" ) - self.variables = _check_init_parameter_variables(variables) + self.variables = _check_variables_input_value(variables) self.random_state = random_state self.seed = seed self.seeding_method = seeding_method @@ -190,7 +190,7 @@ def fit(self, X: pd.DataFrame, y: Optional[pd.Series] = None): # check the variables assigned to the random state if self.seed == "observation": - self.random_state = _check_init_parameter_variables(self.random_state) + self.random_state = _check_variables_input_value(self.random_state) if isinstance(self.random_state, (int, str)): self.random_state = [self.random_state] if self.random_state and any( diff --git a/feature_engine/outliers/artbitrary.py b/feature_engine/outliers/artbitrary.py index 3d33f978e..6804307fa 100644 --- a/feature_engine/outliers/artbitrary.py +++ b/feature_engine/outliers/artbitrary.py @@ -6,7 +6,7 @@ import pandas as pd -from feature_engine._check_input_parameters.check_input_dictionary import ( +from feature_engine._check_init_parameters.check_input_dictionary import ( _check_numerical_dict, ) from feature_engine._docstrings.fit_attributes import ( diff --git a/feature_engine/outliers/base_outlier.py b/feature_engine/outliers/base_outlier.py index 0aa4ca8a9..dd495bc15 100644 --- a/feature_engine/outliers/base_outlier.py +++ b/feature_engine/outliers/base_outlier.py @@ -12,8 +12,8 @@ check_X, ) from feature_engine.tags import _return_tags -from feature_engine.variable_handling._init_parameter_checks import ( - _check_init_parameter_variables, +from feature_engine._check_init_parameters.check_variables import ( + _check_variables_input_value, ) from feature_engine.variable_handling.variable_type_selection import ( find_or_check_numerical_variables, @@ -176,7 +176,7 @@ def __init__( self.capping_method = capping_method self.tail = tail self.fold = 0.05 if (capping_method == "quantiles") & (fold == 3) else fold - self.variables = _check_init_parameter_variables(variables) + self.variables = _check_variables_input_value(variables) self.missing_values = missing_values def fit(self, X: pd.DataFrame, y: Optional[pd.Series] = None): diff --git a/feature_engine/selection/base_recursive_selector.py b/feature_engine/selection/base_recursive_selector.py index fd7f188ea..977374c91 100644 --- a/feature_engine/selection/base_recursive_selector.py +++ b/feature_engine/selection/base_recursive_selector.py @@ -6,8 +6,8 @@ from feature_engine.dataframe_checks import check_X_y from feature_engine.selection.base_selector import BaseSelector, get_feature_importances from feature_engine.tags import _return_tags -from feature_engine.variable_handling._init_parameter_checks import ( - _check_init_parameter_variables, +from feature_engine._check_init_parameters.check_variables import ( + _check_variables_input_value, ) from feature_engine.variable_handling.variable_type_selection import ( find_or_check_numerical_variables, @@ -110,7 +110,7 @@ def __init__( raise ValueError("threshold can only be integer or float") super().__init__(confirm_variables) - self.variables = _check_init_parameter_variables(variables) + self.variables = _check_variables_input_value(variables) self.estimator = estimator self.scoring = scoring self.threshold = threshold diff --git a/feature_engine/selection/drop_constant_features.py b/feature_engine/selection/drop_constant_features.py index 1081e2a61..e5a70e774 100644 --- a/feature_engine/selection/drop_constant_features.py +++ b/feature_engine/selection/drop_constant_features.py @@ -19,8 +19,8 @@ ) from feature_engine.selection.base_selector import BaseSelector from feature_engine.tags import _return_tags -from feature_engine.variable_handling._init_parameter_checks import ( - _check_init_parameter_variables, +from feature_engine._check_init_parameters.check_variables import ( + _check_variables_input_value, ) from feature_engine.variable_handling.variable_type_selection import find_all_variables @@ -156,7 +156,7 @@ def __init__( super().__init__(confirm_variables) self.tol = tol - self.variables = _check_init_parameter_variables(variables) + self.variables = _check_variables_input_value(variables) self.missing_values = missing_values def fit(self, X: pd.DataFrame, y: pd.Series = None): diff --git a/feature_engine/selection/drop_correlated_features.py b/feature_engine/selection/drop_correlated_features.py index 6fb5d43c9..9fc4bb0c6 100644 --- a/feature_engine/selection/drop_correlated_features.py +++ b/feature_engine/selection/drop_correlated_features.py @@ -23,8 +23,8 @@ _variables_numerical_docstring, ) from feature_engine.selection.base_selector import BaseSelector -from feature_engine.variable_handling._init_parameter_checks import ( - _check_init_parameter_variables, +from feature_engine._check_init_parameters.check_variables import ( + _check_variables_input_value, ) from feature_engine.variable_handling.variable_type_selection import ( find_or_check_numerical_variables, @@ -145,7 +145,7 @@ def __init__( super().__init__(confirm_variables) - self.variables = _check_init_parameter_variables(variables) + self.variables = _check_variables_input_value(variables) self.method = method self.threshold = threshold self.missing_values = missing_values diff --git a/feature_engine/selection/drop_duplicate_features.py b/feature_engine/selection/drop_duplicate_features.py index f529f4176..d891f2111 100644 --- a/feature_engine/selection/drop_duplicate_features.py +++ b/feature_engine/selection/drop_duplicate_features.py @@ -21,8 +21,8 @@ ) from feature_engine.selection.base_selector import BaseSelector from feature_engine.tags import _return_tags -from feature_engine.variable_handling._init_parameter_checks import ( - _check_init_parameter_variables, +from feature_engine._check_init_parameters.check_variables import ( + _check_variables_input_value, ) from feature_engine.variable_handling.variable_type_selection import find_all_variables @@ -118,7 +118,7 @@ def __init__( super().__init__(confirm_variables) - self.variables = _check_init_parameter_variables(variables) + self.variables = _check_variables_input_value(variables) self.missing_values = missing_values def fit(self, X: pd.DataFrame, y: pd.Series = None): diff --git a/feature_engine/selection/drop_psi_features.py b/feature_engine/selection/drop_psi_features.py index 20457ce81..406e94dce 100644 --- a/feature_engine/selection/drop_psi_features.py +++ b/feature_engine/selection/drop_psi_features.py @@ -30,8 +30,8 @@ ) from feature_engine.selection.base_selector import BaseSelector from feature_engine.tags import _return_tags -from feature_engine.variable_handling._init_parameter_checks import ( - _check_init_parameter_variables, +from feature_engine._check_init_parameters.check_variables import ( + _check_variables_input_value, ) from feature_engine.variable_handling.variable_type_selection import ( find_categorical_and_numerical_variables, @@ -385,7 +385,7 @@ def __init__( super().__init__(confirm_variables) # Check the variables before assignment. - self.variables = _check_init_parameter_variables(variables) + self.variables = _check_variables_input_value(variables) # Set all remaining arguments as attributes. self.split_col = split_col diff --git a/feature_engine/selection/information_value.py b/feature_engine/selection/information_value.py index f42a305ad..109d3f6dd 100644 --- a/feature_engine/selection/information_value.py +++ b/feature_engine/selection/information_value.py @@ -27,8 +27,8 @@ ) from feature_engine.selection.base_selector import BaseSelector from feature_engine.tags import _return_tags -from feature_engine.variable_handling._init_parameter_checks import ( - _check_init_parameter_variables, +from feature_engine._check_init_parameters.check_variables import ( + _check_variables_input_value, ) from feature_engine.variable_handling.variable_type_selection import ( find_all_variables, @@ -186,7 +186,7 @@ def __init__( "instead." ) - self.variables = _check_init_parameter_variables(variables) + self.variables = _check_variables_input_value(variables) self.bins = bins self.strategy = strategy self.threshold = threshold diff --git a/feature_engine/selection/shuffle_features.py b/feature_engine/selection/shuffle_features.py index cb93917b9..fbbcbdf32 100644 --- a/feature_engine/selection/shuffle_features.py +++ b/feature_engine/selection/shuffle_features.py @@ -32,8 +32,8 @@ ) from feature_engine.selection.base_selector import BaseSelector from feature_engine.tags import _return_tags -from feature_engine.variable_handling._init_parameter_checks import ( - _check_init_parameter_variables, +from feature_engine._check_init_parameters.check_variables import ( + _check_variables_input_value, ) from feature_engine.variable_handling.variable_type_selection import ( find_or_check_numerical_variables, @@ -178,7 +178,7 @@ def __init__( super().__init__(confirm_variables) - self.variables = _check_init_parameter_variables(variables) + self.variables = _check_variables_input_value(variables) self.estimator = estimator self.scoring = scoring self.threshold = threshold diff --git a/feature_engine/selection/single_feature_performance.py b/feature_engine/selection/single_feature_performance.py index 35e95336f..f346bd838 100644 --- a/feature_engine/selection/single_feature_performance.py +++ b/feature_engine/selection/single_feature_performance.py @@ -29,8 +29,8 @@ ) from feature_engine.selection.base_selector import BaseSelector from feature_engine.tags import _return_tags -from feature_engine.variable_handling._init_parameter_checks import ( - _check_init_parameter_variables, +from feature_engine._check_init_parameters.check_variables import ( + _check_variables_input_value, ) from feature_engine.variable_handling.variable_type_selection import ( find_or_check_numerical_variables, @@ -169,7 +169,7 @@ def __init__( ) super().__init__(confirm_variables) - self.variables = _check_init_parameter_variables(variables) + self.variables = _check_variables_input_value(variables) self.estimator = estimator self.scoring = scoring self.threshold = threshold diff --git a/feature_engine/selection/smart_correlation_selection.py b/feature_engine/selection/smart_correlation_selection.py index 5c51c0ef9..718b0777b 100644 --- a/feature_engine/selection/smart_correlation_selection.py +++ b/feature_engine/selection/smart_correlation_selection.py @@ -27,8 +27,8 @@ _variables_numerical_docstring, ) from feature_engine.selection.base_selector import BaseSelector -from feature_engine.variable_handling._init_parameter_checks import ( - _check_init_parameter_variables, +from feature_engine._check_init_parameters.check_variables import ( + _check_variables_input_value, ) from feature_engine.variable_handling.variable_type_selection import ( find_or_check_numerical_variables, @@ -229,7 +229,7 @@ def __init__( super().__init__(confirm_variables) - self.variables = _check_init_parameter_variables(variables) + self.variables = _check_variables_input_value(variables) self.method = method self.threshold = threshold self.missing_values = missing_values diff --git a/feature_engine/selection/target_mean_selection.py b/feature_engine/selection/target_mean_selection.py index 0d534b061..aa00c3faa 100644 --- a/feature_engine/selection/target_mean_selection.py +++ b/feature_engine/selection/target_mean_selection.py @@ -32,8 +32,8 @@ ) from feature_engine.selection.base_selector import BaseSelector from feature_engine.tags import _return_tags -from feature_engine.variable_handling._init_parameter_checks import ( - _check_init_parameter_variables, +from feature_engine._check_init_parameters.check_variables import ( + _check_variables_input_value, ) from feature_engine.variable_handling.variable_type_selection import find_all_variables @@ -245,7 +245,7 @@ def __init__( ) super().__init__(confirm_variables) - self.variables = _check_init_parameter_variables(variables) + self.variables = _check_variables_input_value(variables) self.bins = bins self.strategy = strategy self.scoring = scoring diff --git a/feature_engine/timeseries/forecasting/base_forecast_transformers.py b/feature_engine/timeseries/forecasting/base_forecast_transformers.py index 083ff6d7a..dac795ee0 100644 --- a/feature_engine/timeseries/forecasting/base_forecast_transformers.py +++ b/feature_engine/timeseries/forecasting/base_forecast_transformers.py @@ -22,8 +22,8 @@ check_X, ) from feature_engine.tags import _return_tags -from feature_engine.variable_handling._init_parameter_checks import ( - _check_init_parameter_variables, +from feature_engine._check_init_parameters.check_variables import ( + _check_variables_input_value, ) from feature_engine.variable_handling.variable_type_selection import ( find_or_check_numerical_variables, @@ -77,7 +77,7 @@ def __init__( f"Got {drop_original} instead." ) - self.variables = _check_init_parameter_variables(variables) + self.variables = _check_variables_input_value(variables) self.missing_values = missing_values self.drop_original = drop_original diff --git a/feature_engine/transformation/arcsin.py b/feature_engine/transformation/arcsin.py index 196773b28..dded47bc4 100644 --- a/feature_engine/transformation/arcsin.py +++ b/feature_engine/transformation/arcsin.py @@ -22,8 +22,8 @@ ) from feature_engine._docstrings.substitute import Substitution from feature_engine.tags import _return_tags -from feature_engine.variable_handling._init_parameter_checks import ( - _check_init_parameter_variables, +from feature_engine._check_init_parameters.check_variables import ( + _check_variables_input_value, ) @@ -104,7 +104,7 @@ def __init__( self, variables: Union[None, int, str, List[Union[str, int]]] = None ) -> None: - self.variables = _check_init_parameter_variables(variables) + self.variables = _check_variables_input_value(variables) def fit(self, X: pd.DataFrame, y: Optional[pd.Series] = None): """ diff --git a/feature_engine/transformation/boxcox.py b/feature_engine/transformation/boxcox.py index afb90794c..52bbb3be4 100644 --- a/feature_engine/transformation/boxcox.py +++ b/feature_engine/transformation/boxcox.py @@ -22,8 +22,8 @@ ) from feature_engine._docstrings.substitute import Substitution from feature_engine.tags import _return_tags -from feature_engine.variable_handling._init_parameter_checks import ( - _check_init_parameter_variables, +from feature_engine._check_init_parameters.check_variables import ( + _check_variables_input_value, ) @@ -118,7 +118,7 @@ def __init__( self, variables: Union[None, int, str, List[Union[str, int]]] = None ) -> None: - self.variables = _check_init_parameter_variables(variables) + self.variables = _check_variables_input_value(variables) def fit(self, X: pd.DataFrame, y: Optional[pd.Series] = None): """ diff --git a/feature_engine/transformation/log.py b/feature_engine/transformation/log.py index 6928913d3..49601e45c 100644 --- a/feature_engine/transformation/log.py +++ b/feature_engine/transformation/log.py @@ -23,8 +23,8 @@ ) from feature_engine._docstrings.substitute import Substitution from feature_engine.tags import _return_tags -from feature_engine.variable_handling._init_parameter_checks import ( - _check_init_parameter_variables, +from feature_engine._check_init_parameters.check_variables import ( + _check_variables_input_value, ) @@ -106,7 +106,7 @@ def __init__( if base not in ["e", "10"]: raise ValueError("base can take only '10' or 'e' as values") - self.variables = _check_init_parameter_variables(variables) + self.variables = _check_variables_input_value(variables) self.base = base def fit(self, X: pd.DataFrame, y: Optional[pd.Series] = None): @@ -314,7 +314,7 @@ def __init__( if not isinstance(C, (int, float, dict)) and not C == "auto": raise ValueError("C can take only 'auto', integers or floats") - self.variables = _check_init_parameter_variables(variables) + self.variables = _check_variables_input_value(variables) self.base = base self.C = C diff --git a/feature_engine/transformation/power.py b/feature_engine/transformation/power.py index 531b0d189..eb943610b 100644 --- a/feature_engine/transformation/power.py +++ b/feature_engine/transformation/power.py @@ -21,8 +21,8 @@ _inverse_transform_docstring, ) from feature_engine._docstrings.substitute import Substitution -from feature_engine.variable_handling._init_parameter_checks import ( - _check_init_parameter_variables, +from feature_engine._check_init_parameters.check_variables import ( + _check_variables_input_value, ) @@ -104,7 +104,7 @@ def __init__( raise ValueError("exp must be a float or an int") self.exp = exp - self.variables = _check_init_parameter_variables(variables) + self.variables = _check_variables_input_value(variables) def fit(self, X: pd.DataFrame, y: Optional[pd.Series] = None): """ diff --git a/feature_engine/transformation/reciprocal.py b/feature_engine/transformation/reciprocal.py index 71e86eba6..79efe3cbb 100644 --- a/feature_engine/transformation/reciprocal.py +++ b/feature_engine/transformation/reciprocal.py @@ -22,8 +22,8 @@ ) from feature_engine._docstrings.substitute import Substitution from feature_engine.tags import _return_tags -from feature_engine.variable_handling._init_parameter_checks import ( - _check_init_parameter_variables, +from feature_engine._check_init_parameters.check_variables import ( + _check_variables_input_value, ) @@ -96,7 +96,7 @@ class ReciprocalTransformer(BaseNumericalTransformer): def __init__( self, variables: Union[None, int, str, List[Union[str, int]]] = None ) -> None: - self.variables = _check_init_parameter_variables(variables) + self.variables = _check_variables_input_value(variables) def fit(self, X: pd.DataFrame, y: Optional[pd.Series] = None): """ diff --git a/feature_engine/transformation/yeojohnson.py b/feature_engine/transformation/yeojohnson.py index 1285e341f..5760c04a5 100644 --- a/feature_engine/transformation/yeojohnson.py +++ b/feature_engine/transformation/yeojohnson.py @@ -22,8 +22,8 @@ ) from feature_engine._docstrings.substitute import Substitution from feature_engine.tags import _return_tags -from feature_engine.variable_handling._init_parameter_checks import ( - _check_init_parameter_variables, +from feature_engine._check_init_parameters.check_variables import ( + _check_variables_input_value, ) @@ -111,7 +111,7 @@ class YeoJohnsonTransformer(BaseNumericalTransformer): def __init__( self, variables: Union[None, int, str, List[Union[str, int]]] = None ) -> None: - self.variables = _check_init_parameter_variables(variables) + self.variables = _check_variables_input_value(variables) def fit(self, X: pd.DataFrame, y: Optional[pd.Series] = None): """ diff --git a/feature_engine/variable_handling/_init_parameter_checks.py b/feature_engine/variable_handling/_init_parameter_checks.py deleted file mode 100644 index dd0af1a5e..000000000 --- a/feature_engine/variable_handling/_init_parameter_checks.py +++ /dev/null @@ -1,34 +0,0 @@ -from typing import Any - -from feature_engine.variable_handling.variable_type_selection import Variables - - -# set return value typehint to Any to avoid issues with the base transformer fit method -def _check_init_parameter_variables(variables: Variables) -> Any: - """ - Checks that the input is of the correct type. Allowed values are None, int, str or - list of strings and ints. - - Parameters - ---------- - variables : string, int, list of strings, list of integers. Default=None - - Returns - ------- - variables: same as input - """ - - msg = "variables should be a string, an int or a list of strings or integers." - msg_dupes = "the list contains duplicated variable names" - - if variables: - if isinstance(variables, list): - if not all(isinstance(i, (str, int)) for i in variables): - raise ValueError(msg) - if len(variables) != len(set(variables)): - raise ValueError(msg_dupes) - else: - if not isinstance(variables, (str, int)): - raise ValueError(msg) - - return variables diff --git a/feature_engine/wrappers/wrappers.py b/feature_engine/wrappers/wrappers.py index a621a85b5..ad57afb48 100644 --- a/feature_engine/wrappers/wrappers.py +++ b/feature_engine/wrappers/wrappers.py @@ -6,8 +6,8 @@ from feature_engine.dataframe_checks import _check_X_matches_training_df, check_X from feature_engine.tags import _return_tags -from feature_engine.variable_handling._init_parameter_checks import ( - _check_init_parameter_variables, +from feature_engine._check_init_parameters.check_variables import ( + _check_variables_input_value, ) from feature_engine.variable_handling.variable_type_selection import ( find_all_variables, @@ -233,7 +233,7 @@ def __init__( ) self.transformer = transformer - self.variables = _check_init_parameter_variables(variables) + self.variables = _check_variables_input_value(variables) def fit(self, X: pd.DataFrame, y: Optional[str] = None): """ diff --git a/tests/test_check_input_parameters/test_check_init_input_params.py b/tests/test_check_input_parameters/test_check_init_input_params.py index b216d4cce..4f4b7f631 100644 --- a/tests/test_check_input_parameters/test_check_init_input_params.py +++ b/tests/test_check_input_parameters/test_check_init_input_params.py @@ -1,6 +1,6 @@ import pytest -from feature_engine._check_input_parameters.check_init_input_params import ( +from feature_engine._check_init_parameters.check_init_input_params import ( _check_param_drop_original, _check_param_missing_values, ) diff --git a/tests/test_check_input_parameters/test_check_input_dictionary.py b/tests/test_check_input_parameters/test_check_input_dictionary.py index 9ef57ad98..925743dd2 100644 --- a/tests/test_check_input_parameters/test_check_input_dictionary.py +++ b/tests/test_check_input_parameters/test_check_input_dictionary.py @@ -1,6 +1,6 @@ import pytest -from feature_engine._check_input_parameters.check_input_dictionary import ( +from feature_engine._check_init_parameters.check_input_dictionary import ( _check_numerical_dict, ) diff --git a/tests/test_check_input_parameters/test_check_variables.py b/tests/test_check_input_parameters/test_check_variables.py new file mode 100644 index 000000000..9c95befe0 --- /dev/null +++ b/tests/test_check_input_parameters/test_check_variables.py @@ -0,0 +1,45 @@ +import pytest + +from feature_engine._check_init_parameters.check_variables import ( + _check_variables_input_value, +) + + +@pytest.mark.parametrize("_input_vars", [("var1", "var2"), {"var1": 1, "var2": 2}]) +def test_raises_errors_when_not_list_str_or_int(_input_vars): + with pytest.raises(ValueError)as record: + assert _check_variables_input_value(_input_vars) + msg = ( + "`variables` should contain a string, an integer or a list of strings or " + f"integers. Got {_input_vars} instead." + ) + assert str(record.value) == msg + + +@pytest.mark.parametrize( + "_input_vars", [["var1", "var2", "var2", "var3"], [0, 1, 1, 2]] +) +def test_raises_error_when_duplicated_var_names(_input_vars): + with pytest.raises(ValueError) as record: + assert _check_variables_input_value(_input_vars) + msg = "The list entered in `variables` contains duplicated variable names." + assert str(record.value) == msg + + +def test_raises_error_when_empty_list(): + with pytest.raises(ValueError) as record: + assert _check_variables_input_value([]) + msg = "The list of `variables` is empty." + assert str(record.value) == msg + + +@pytest.mark.parametrize( + "_input_vars", + [["var1", "var2", "var3"], [0, 1, 2, 3], "var1", ["var1"], 0, [0]], +) +def test_return_variables(_input_vars): + assert _check_variables_input_value(_input_vars) == _input_vars + + +def test_return_when_variables_is_none(): + assert _check_variables_input_value(None) is None diff --git a/tests/test_variable_handling/test_init_parameter_checks.py b/tests/test_variable_handling/test_init_parameter_checks.py deleted file mode 100644 index 23f398730..000000000 --- a/tests/test_variable_handling/test_init_parameter_checks.py +++ /dev/null @@ -1,31 +0,0 @@ -import pytest - -from feature_engine.variable_handling._init_parameter_checks import ( - _check_init_parameter_variables, -) - - -@pytest.mark.parametrize( - "_input_vars", - [ - ("var1", "var2"), - {"var1": 1, "var2": 2}, - ["var1", "var2", "var2", "var3"], - [0, 1, 1, 2], - ], -) -def test_check_init_parameter_variables_raises_errors(_input_vars): - with pytest.raises(ValueError): - assert _check_init_parameter_variables(_input_vars) - - -@pytest.mark.parametrize( - "_input_vars", - [["var1", "var2", "var3"], [0, 1, 2, 3], "var1", ["var1"], 0, [0]], -) -def test_check_init_parameter_variables(_input_vars): - assert _check_init_parameter_variables(_input_vars) == _input_vars - - -def test_check_init_parameter_variables_is_none(): - assert _check_init_parameter_variables(None) is None