diff --git a/feature_engine/encoding/count_frequency.py b/feature_engine/encoding/count_frequency.py index 1a9825de6..3d063c7dc 100644 --- a/feature_engine/encoding/count_frequency.py +++ b/feature_engine/encoding/count_frequency.py @@ -220,11 +220,6 @@ def fit(self, X: IntoDataFrame, y: Optional[IntoSeries] = None): variables_ = self._check_or_select_variables(X) self._check_na(X, variables_) - if self.encoding_method not in ["count", "frequency"]: - raise ValueError( - "Unrecognized value for encoding_method. It should be 'count' or " - f"'frequency'. Got {self.encoding_method} instead." - ) normalize = self.encoding_method == "frequency" self.encoder_dict_ = {} diff --git a/tests/backend_helpers.py b/tests/backend_helpers.py new file mode 100644 index 000000000..44032496f --- /dev/null +++ b/tests/backend_helpers.py @@ -0,0 +1,38 @@ +"""Helpers for tests that run on several dataframe backends. +Use them together with the `make_df` fixture in `tests/conftest.py`. +""" + +import narwhals as nw +import pandas as pd +import polars as pl + + +def frame_to_dict(X): + """Return the dataframe contents as ``{column: list of values}``. + + pandas represents missing values as NaN and polars as None, so NaN (and + pd.NA) are normalised to None and the same expected values work for both + backends. + """ + result = nw.from_native(X, eager_only=True).to_dict(as_series=False) + return { + col: [none_if_missing(v) for v in values] for col, values in result.items() + } + + +def null_count(X, col): + """Return the number of missing values in column ``col``.""" + return nw.from_native(X, eager_only=True).get_column(col).null_count() + + +def make_series(make_df, values, name=None): + """Build a Series on the same backend as ``make_df``.""" + if make_df is pd.DataFrame: + return pd.Series(values, name=name) + return pl.Series(name=name or "", values=values) + + +def none_if_missing(value): + if value is pd.NA or (isinstance(value, float) and value != value): + return None + return value diff --git a/tests/conftest.py b/tests/conftest.py index 721b8b5f3..88fe8f3d5 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -1,8 +1,19 @@ import numpy as np import pandas as pd +import polars as pl import pytest +@pytest.fixture(params=[pd.DataFrame, pl.DataFrame], ids=["pandas", "polars"]) +def make_df(request): + """Dataframe constructor of the backend under test: pandas or polars. + + A test that requests this fixture runs once per backend. Build the input + with ``make_df(data)`` and check the output with ``isinstance(X, make_df)``. + """ + return request.param + + @pytest.fixture(scope="module") def df_vartypes(): data = { diff --git a/tests/test_encoding/conftest.py b/tests/test_encoding/conftest.py new file mode 100644 index 000000000..24387fa0c --- /dev/null +++ b/tests/test_encoding/conftest.py @@ -0,0 +1,111 @@ +"""Data shared by the encoder tests. + +Each fixture returns a fresh dict, so tests can build the dataframe on the +backend under test with `make_df(data)`. Missing values are written as None, +which both pandas and polars read as missing. +""" + +import pytest + +TARGET = [1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 1, 1, 0, 0] + + +@pytest.fixture +def data_enc(): + return { + "var_A": ["A"] * 6 + ["B"] * 10 + ["C"] * 4, + "var_B": ["A"] * 10 + ["B"] * 6 + ["C"] * 4, + "target": list(TARGET), + } + + +@pytest.fixture +def data_enc_rare(): + return { + "var_A": ["B"] * 9 + ["A"] * 6 + ["C"] * 4 + ["D"] * 1, + "var_B": ["A"] * 10 + ["B"] * 6 + ["C"] * 4, + "target": list(TARGET), + } + + +@pytest.fixture +def data_enc_na(): + return { + "var_A": [None] + ["B"] * 8 + ["A"] * 6 + ["C"] * 4 + ["D"] * 1, + "var_B": ["A"] * 10 + ["B"] * 6 + ["C"] * 4, + "target": list(TARGET), + } + + +@pytest.fixture +def data_enc_numeric(): + return { + "var_A": [1] * 6 + [2] * 10 + [3] * 4, + "var_B": [1] * 10 + [2] * 6 + [3] * 4, + "target": list(TARGET), + } + + +def _data_enc_big(): + return { + "var_A": ["A"] * 6 + + ["B"] * 10 + + ["C"] * 4 + + ["D"] * 10 + + ["E"] * 2 + + ["F"] * 2 + + ["G"] * 6, + "var_B": ["A"] * 10 + + ["B"] * 6 + + ["C"] * 4 + + ["D"] * 10 + + ["E"] * 2 + + ["F"] * 2 + + ["G"] * 6, + "var_C": ["A"] * 4 + + ["B"] * 6 + + ["C"] * 10 + + ["D"] * 10 + + ["E"] * 2 + + ["F"] * 2 + + ["G"] * 6, + } + + +@pytest.fixture +def data_enc_big(): + return _data_enc_big() + + +@pytest.fixture +def data_enc_big_na(): + data = _data_enc_big() + data["var_A"][0] = None + return data + + +@pytest.fixture +def data_enc_top(): + return { + "var_A": ["A"] * 5 + + ["B"] * 11 + + ["C"] * 4 + + ["D"] * 9 + + ["E"] * 2 + + ["F"] * 2 + + ["G"] * 7, + "var_B": ["A"] * 11 + + ["B"] * 7 + + ["C"] * 4 + + ["D"] * 9 + + ["E"] * 2 + + ["F"] * 2 + + ["G"] * 5, + "var_C": ["A"] * 4 + + ["B"] * 5 + + ["C"] * 11 + + ["D"] * 9 + + ["E"] * 2 + + ["F"] * 2 + + ["G"] * 7, + } diff --git a/tests/test_encoding/test_count_frequency_encoder.py b/tests/test_encoding/test_count_frequency_encoder.py index b4460c0da..b7445f6c7 100644 --- a/tests/test_encoding/test_count_frequency_encoder.py +++ b/tests/test_encoding/test_count_frequency_encoder.py @@ -1,29 +1,13 @@ import re import warnings -import narwhals as nw import pandas as pd -import polars as pl import pytest from sklearn.exceptions import NotFittedError from feature_engine.encoding import CountEncoder, CountFrequencyEncoder +from tests.backend_helpers import null_count, frame_to_dict -DATA_ENC = { - "var_A": ["A"] * 6 + ["B"] * 10 + ["C"] * 4, - "var_B": ["A"] * 10 + ["B"] * 6 + ["C"] * 4, - "target": [1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 1, 1, 0, 0], -} -DATA_ENC_RARE = { - "var_A": ["B"] * 9 + ["A"] * 6 + ["C"] * 4 + ["D"] * 1, - "var_B": ["A"] * 10 + ["B"] * 6 + ["C"] * 4, - "target": [1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 1, 1, 0, 0], -} -DATA_ENC_NA = { - "var_A": [None] + ["B"] * 8 + ["A"] * 6 + ["C"] * 4 + ["D"] * 1, - "var_B": ["A"] * 10 + ["B"] * 6 + ["C"] * 4, - "target": [1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 1, 1, 0, 0], -} DATA_VARTYPES = { "Name": ["tom", "nick", "krish", "jack"], "City": ["London", "Manchester", "Liverpool", "Bristol"], @@ -33,25 +17,14 @@ } -def _to_dict(X): - # to_dict(as_series=False) is a convenient, backend-agnostic way to read - # values back out for comparison, regardless of pandas vs polars. pandas - # returns NaN where polars returns None, so normalise NaN to None. - result = nw.from_native(X, eager_only=True).to_dict(as_series=False) - return { - c: [None if isinstance(v, float) and v != v else v for v in values] - for c, values in result.items() - } - - -def _null_count(X, col): - return nw.from_native(X, eager_only=True)[col].null_count() - - # init parameters @pytest.mark.parametrize("enc_method", ["arbitrary", False, 1]) def test_error_if_encoding_method_not_permitted_value(enc_method): - with pytest.raises(ValueError): + msg = ( + "encoding_method takes only values 'count' and 'frequency'. " + f"Got {enc_method} instead." + ) + with pytest.raises(ValueError, match=msg): CountEncoder(encoding_method=enc_method) @@ -59,7 +32,11 @@ def test_error_if_encoding_method_not_permitted_value(enc_method): "errors", ["empanada", False, 1, ("raise", "ignore"), ["ignore"]] ) def test_error_if_unseen_gets_not_permitted_value(errors): - with pytest.raises(ValueError): + msg = ( + "Parameter `unseen` takes only values ignore, raise, encode. " + f"Got {errors} instead." + ) + with pytest.raises(ValueError, match=re.escape(msg)): CountEncoder(unseen=errors) @@ -80,39 +57,29 @@ def test_init_param_assignment(params): # fit and transform -@pytest.mark.parametrize("make_df", [pd.DataFrame, pl.DataFrame]) -def test_encode_1_variable_with_counts(make_df): +def test_encode_1_variable_with_counts(make_df, data_enc): # test case 1: 1 variable, counts - df_enc = make_df(DATA_ENC) encoder = CountEncoder(encoding_method="count", variables=["var_A"]) - X = encoder.fit_transform(df_enc) + X = encoder.fit_transform(make_df(data_enc)) - # init params - assert encoder.encoding_method == "count" - assert encoder.variables == ["var_A"] # fit params assert encoder.variables_ == ["var_A"] assert encoder.encoder_dict_ == {"var_A": {"A": 6, "B": 10, "C": 4}} assert encoder.n_features_in_ == 3 # transform params assert isinstance(X, make_df) - assert _to_dict(X) == { + assert frame_to_dict(X) == { "var_A": [6] * 6 + [10] * 10 + [4] * 4, - "var_B": DATA_ENC["var_B"], - "target": DATA_ENC["target"], + "var_B": data_enc["var_B"], + "target": data_enc["target"], } -@pytest.mark.parametrize("make_df", [pd.DataFrame, pl.DataFrame]) -def test_automatically_select_variables_encode_with_frequency(make_df): +def test_automatically_select_variables_encode_with_frequency(make_df, data_enc): # test case 2: automatically select variables, frequency - df_enc = make_df(DATA_ENC) encoder = CountEncoder(encoding_method="frequency", variables=None) - X = encoder.fit_transform(df_enc) + X = encoder.fit_transform(make_df(data_enc)) - # init params - assert encoder.encoding_method == "frequency" - assert encoder.variables is None # fit params assert encoder.variables_ == ["var_A", "var_B"] assert encoder.encoder_dict_ == { @@ -122,22 +89,19 @@ def test_automatically_select_variables_encode_with_frequency(make_df): assert encoder.n_features_in_ == 3 # transform params assert isinstance(X, make_df) - assert _to_dict(X) == { + assert frame_to_dict(X) == { "var_A": [0.3] * 6 + [0.5] * 10 + [0.2] * 4, "var_B": [0.5] * 10 + [0.3] * 6 + [0.2] * 4, - "target": DATA_ENC["target"], + "target": data_enc["target"], } -@pytest.mark.parametrize("make_df", [pd.DataFrame, pl.DataFrame]) -def test_encoding_when_nan_in_fit_df(make_df): - df_enc = make_df(DATA_ENC) - +def test_encoding_when_nan_in_fit_df(make_df, data_enc): encoder = CountEncoder( encoding_method="frequency", missing_values="ignore", ) - encoder.fit(df_enc) + encoder.fit(make_df(data_enc)) X = encoder.transform( make_df({"var_A": ["A", None], "var_B": ["A", None], "target": [1, 0]}) @@ -145,45 +109,32 @@ def test_encoding_when_nan_in_fit_df(make_df): # transform params assert isinstance(X, make_df) - assert _to_dict(X) == {"var_A": [0.3, None], "var_B": [0.5, None], "target": [1, 0]} - - -@pytest.mark.parametrize("make_df", [pd.DataFrame, pl.DataFrame]) -@pytest.mark.parametrize("enc_method", ["arbitrary", False, 1]) -def test_error_if_encoding_method_not_recognized_in_fit(enc_method, make_df): - df_enc = make_df(DATA_ENC) - enc = CountEncoder() - enc.encoding_method = enc_method - msg = ( - "Unrecognized value for encoding_method. It should be 'count' or " - f"'frequency'. Got {enc_method} instead." - ) - with pytest.raises(ValueError, match=re.escape(msg)): - enc.fit(df_enc) + assert frame_to_dict(X) == { + "var_A": [0.3, None], + "var_B": [0.5, None], + "target": [1, 0], + } -@pytest.mark.parametrize("make_df", [pd.DataFrame, pl.DataFrame]) -def test_warning_when_df_contains_unseen_categories(make_df): +def test_warning_when_df_contains_unseen_categories( + make_df, data_enc, data_enc_rare +): # dataset to be transformed contains categories not present in # training dataset (unseen categories), unseen set to ignore. - df_enc = make_df(DATA_ENC) - df_enc_rare = make_df(DATA_ENC_RARE) - msg = "During the encoding, NaN values were introduced in the feature(s) var_A." # check for warning when unseen equals 'ignore' encoder = CountEncoder(unseen="ignore") - encoder.fit(df_enc) + encoder.fit(make_df(data_enc)) with pytest.warns(UserWarning, match=re.escape(msg)): - encoder.transform(df_enc_rare) + encoder.transform(make_df(data_enc_rare)) -@pytest.mark.parametrize("make_df", [pd.DataFrame, pl.DataFrame]) -def test_error_when_df_contains_unseen_categories(make_df): +def test_error_when_df_contains_unseen_categories(make_df, data_enc, data_enc_rare): # dataset to be transformed contains categories not present in # training dataset (unseen categories), unseen set to raise. - df_enc = make_df(DATA_ENC) - df_enc_rare = make_df(DATA_ENC_RARE) + df_enc = make_df(data_enc) + df_enc_rare = make_df(data_enc_rare) msg = "During the encoding, NaN values were introduced in the feature(s) var_A." @@ -194,36 +145,10 @@ def test_error_when_df_contains_unseen_categories(make_df): with pytest.raises(ValueError, match=re.escape(msg)): encoder.transform(df_enc_rare) - # check for no error and no warning when unseen equals 'encode' - with warnings.catch_warnings(): - warnings.simplefilter("error") - encoder = CountEncoder(unseen="encode") - encoder.fit(df_enc) - encoder.transform(df_enc_rare) - - -@pytest.mark.parametrize("make_df", [pd.DataFrame, pl.DataFrame]) -def test_no_error_triggered_when_df_contains_unseen_categories_and_unseen_is_encode( - make_df, -): - # dataset to be transformed contains categories not present in - # training dataset (unseen categories). - df_enc = make_df(DATA_ENC) - df_enc_rare = make_df(DATA_ENC_RARE) - - # check for no error and no warning when unseen equals 'encode' - warnings.simplefilter("error") - encoder = CountEncoder(unseen="encode") - encoder.fit(df_enc) - with warnings.catch_warnings(): - encoder.transform(df_enc_rare) - -@pytest.mark.parametrize("make_df", [pd.DataFrame, pl.DataFrame]) @pytest.mark.parametrize("errors", ["raise", "ignore", "encode"]) -def test_fit_raises_error_if_df_contains_na(errors, make_df): +def test_fit_raises_error_if_df_contains_na(errors, make_df, data_enc_na): # test case 4: when dataset contains na, fit method - df_enc_na = make_df(DATA_ENC_NA) encoder = CountEncoder(unseen=errors) msg = ( "Some of the variables in the dataset contain NaN. Check and " @@ -231,48 +156,25 @@ def test_fit_raises_error_if_df_contains_na(errors, make_df): "`missing_values='ignore'` when initialising this transformer." ) with pytest.raises(ValueError, match=re.escape(msg)): - encoder.fit(df_enc_na) + encoder.fit(make_df(data_enc_na)) -@pytest.mark.parametrize("make_df", [pd.DataFrame, pl.DataFrame]) @pytest.mark.parametrize("errors", ["raise", "ignore", "encode"]) -def test_transform_raises_error_if_df_contains_na(errors, make_df): +def test_transform_raises_error_if_df_contains_na( + errors, make_df, data_enc, data_enc_na +): # test case 4: when dataset contains na, transform method - df_enc = make_df(DATA_ENC) - df_enc_na = make_df(DATA_ENC_NA) encoder = CountEncoder(unseen=errors) - encoder.fit(df_enc) + encoder.fit(make_df(data_enc)) msg = ( "Some of the variables in the dataset contain NaN. Check and " "remove those before using this transformer or set the parameter " "`missing_values='ignore'` when initialising this transformer." ) with pytest.raises(ValueError, match=re.escape(msg)): - encoder.transform(df_enc_na) - - -@pytest.mark.parametrize("make_df", [pd.DataFrame, pl.DataFrame]) -def test_zero_encoding_for_new_categories(make_df): - df_fit = make_df( - {"col1": ["a", "a", "b", "a", "c"], "col2": ["1", "2", "3", "1", "2"]} - ) - df_transf = make_df( - {"col1": ["a", "d", "b", "a", "c"], "col2": ["1", "2", "3", "1", "4"]} - ) - encoder = CountEncoder(unseen="encode").fit(df_fit) - - result = encoder.transform(df_transf) - assert isinstance(result, make_df) - - # check that no NaNs are added - assert _null_count(result, "col1") == 0 - assert _null_count(result, "col2") == 0 - - # check that the counts are correct for both new and old - assert _to_dict(result) == {"col1": [3, 0, 1, 3, 1], "col2": [2, 2, 1, 2, 0]} + encoder.transform(make_df(data_enc_na)) -@pytest.mark.parametrize("make_df", [pd.DataFrame, pl.DataFrame]) def test_zero_encoding_for_unseen_categories_if_unseen_is_encode(make_df): df_fit = make_df( {"col1": ["a", "a", "b", "a", "c"], "col2": ["1", "2", "3", "1", "2"]} @@ -283,33 +185,38 @@ def test_zero_encoding_for_unseen_categories_if_unseen_is_encode(make_df): # count encoding encoder = CountEncoder(unseen="encode").fit(df_fit) - result = encoder.transform(df_transform) + # unseen categories are encoded without raising or warning + with warnings.catch_warnings(): + warnings.simplefilter("error") + result = encoder.transform(df_transform) assert isinstance(result, make_df) # check that no NaNs are added - assert _null_count(result, "col1") == 0 - assert _null_count(result, "col2") == 0 + assert null_count(result, "col1") == 0 + assert null_count(result, "col2") == 0 # check that the counts are correct - assert _to_dict(result) == {"col1": [3, 0, 1, 3, 1], "col2": [2, 2, 1, 2, 0]} + assert frame_to_dict(result) == {"col1": [3, 0, 1, 3, 1], "col2": [2, 2, 1, 2, 0]} # with frequency encoder = CountEncoder(encoding_method="frequency", unseen="encode").fit(df_fit) - result = encoder.transform(df_transform) + # unseen categories are encoded without raising or warning + with warnings.catch_warnings(): + warnings.simplefilter("error") + result = encoder.transform(df_transform) assert isinstance(result, make_df) # check that no NaNs are added - assert _null_count(result, "col1") == 0 - assert _null_count(result, "col2") == 0 + assert null_count(result, "col1") == 0 + assert null_count(result, "col2") == 0 # check that the frequencies are correct - assert _to_dict(result) == { + assert frame_to_dict(result) == { "col1": [0.6, 0, 0.2, 0.6, 0.2], "col2": [0.4, 0.4, 0.2, 0.4, 0], } -@pytest.mark.parametrize("make_df", [pd.DataFrame, pl.DataFrame]) def test_nan_encoding_for_new_categories_if_unseen_is_ignore(make_df): df_fit = make_df( {"col1": ["a", "a", "b", "a", "c"], "col2": ["1", "2", "3", "1", "2"]} @@ -322,33 +229,28 @@ def test_nan_encoding_for_new_categories_if_unseen_is_ignore(make_df): assert isinstance(result, make_df) # check that 1 NaN is added per variable - assert _null_count(result, "col1") == 1 - assert _null_count(result, "col2") == 1 + assert null_count(result, "col1") == 1 + assert null_count(result, "col2") == 1 # check that the counts are correct for both new and old - assert _to_dict(result) == { + assert frame_to_dict(result) == { "col1": [3, None, 1, 3, 1], "col2": [2, 2, 1, 2, None], } -@pytest.mark.parametrize("make_df", [pd.DataFrame, pl.DataFrame]) def test_ignore_variable_format_with_frequency(make_df): - df_vartypes = make_df(DATA_VARTYPES) encoder = CountEncoder( encoding_method="frequency", variables=None, ignore_format=True ) - X = encoder.fit_transform(df_vartypes) + X = encoder.fit_transform(make_df(DATA_VARTYPES)) - # init params - assert encoder.encoding_method == "frequency" - assert encoder.variables is None # fit params assert encoder.variables_ == ["Name", "City", "Age", "Marks", "dob"] assert encoder.n_features_in_ == 5 # transform params assert isinstance(X, make_df) - assert _to_dict(X) == { + assert frame_to_dict(X) == { "Name": [0.25, 0.25, 0.25, 0.25], "City": [0.25, 0.25, 0.25, 0.25], "Age": [0.25, 0.25, 0.25, 0.25], @@ -375,9 +277,6 @@ def test_column_names_are_numbers(df_numeric_columns): transf_df = pd.DataFrame(transf_df) - # init params - assert encoder.encoding_method == "frequency" - assert encoder.variables == [0, 1, 2, 3] # fit params assert encoder.variables_ == [0, 1, 2, 3] assert encoder.n_features_in_ == 5 @@ -402,7 +301,6 @@ def test_variables_cast_as_category(df_enc_category_dtypes): assert X["var_A"].dtypes == float -@pytest.mark.parametrize("make_df", [pd.DataFrame, pl.DataFrame]) def test_inverse_transform_when_no_unseen(make_df): words = ["dog", "dog", "cat", "cat", "cat", "bird"] df = make_df({"words": words}) @@ -411,10 +309,9 @@ def test_inverse_transform_when_no_unseen(make_df): dft = enc.transform(df) X = enc.inverse_transform(dft) assert isinstance(X, make_df) - assert _to_dict(X) == {"words": words} + assert frame_to_dict(X) == {"words": words} -@pytest.mark.parametrize("make_df", [pd.DataFrame, pl.DataFrame]) def test_inverse_transform_when_ignore_unseen(make_df): df1 = make_df({"words": ["dog", "dog", "cat", "cat", "cat", "bird"]}) df2 = make_df({"words": ["dog", "dog", "cat", "cat", "cat", "frog"]}) @@ -423,10 +320,9 @@ def test_inverse_transform_when_ignore_unseen(make_df): dft = enc.transform(df2) X = enc.inverse_transform(dft) assert isinstance(X, make_df) - assert _to_dict(X) == {"words": ["dog", "dog", "cat", "cat", "cat", None]} + assert frame_to_dict(X) == {"words": ["dog", "dog", "cat", "cat", "cat", None]} -@pytest.mark.parametrize("make_df", [pd.DataFrame, pl.DataFrame]) def test_inverse_transform_when_encode_unseen(make_df): df1 = make_df({"words": ["dog", "dog", "cat", "cat", "cat", "bird"]}) df2 = make_df({"words": ["dog", "dog", "cat", "cat", "cat", "frog"]}) @@ -435,10 +331,9 @@ def test_inverse_transform_when_encode_unseen(make_df): dft = enc.transform(df2) X = enc.inverse_transform(dft) assert isinstance(X, make_df) - assert _to_dict(X) == {"words": ["dog", "dog", "cat", "cat", "cat", None]} + assert frame_to_dict(X) == {"words": ["dog", "dog", "cat", "cat", "cat", None]} -@pytest.mark.parametrize("make_df", [pd.DataFrame, pl.DataFrame]) def test_inverse_transform_raises_non_fitted_error(make_df): df1 = make_df({"words": ["dog", "dog", "cat", "cat", "cat", "bird"]}) enc = CountEncoder() @@ -457,7 +352,6 @@ def test_inverse_transform_raises_non_fitted_error(make_df): enc.inverse_transform(df1_na) -@pytest.mark.parametrize("make_df", [pd.DataFrame, pl.DataFrame]) def test_count_frequency_encoder_is_deprecated(make_df): """CountFrequencyEncoder should emit a FutureWarning and still work.""" X = make_df({"var_A": ["A"] * 6 + ["B"] * 2 + ["C"] * 2}) @@ -472,4 +366,8 @@ def test_count_frequency_encoder_is_deprecated(make_df): X_new = enc_new.fit_transform(X) assert isinstance(X_old, make_df) assert isinstance(X_new, make_df) - assert _to_dict(X_old) == _to_dict(X_new) == {"var_A": [6] * 6 + [2] * 2 + [2] * 2} + assert ( + frame_to_dict(X_old) + == frame_to_dict(X_new) + == {"var_A": [6] * 6 + [2] * 2 + [2] * 2} + )