From 5a4f9a61a4fdbc26b5a3bb233439bebe136627c4 Mon Sep 17 00:00:00 2001 From: Loc Nguyen Date: Fri, 30 Oct 2026 08:46:23 +0700 Subject: [PATCH] Do not re-add an existing category in CategoricalImputer (#1113) --- feature_engine/imputation/categorical.py | 8 ++++-- .../test_categorical_imputer.py | 27 +++++++++++++++++++ 2 files changed, 33 insertions(+), 2 deletions(-) diff --git a/feature_engine/imputation/categorical.py b/feature_engine/imputation/categorical.py index 2cd4a00a3..995400c57 100644 --- a/feature_engine/imputation/categorical.py +++ b/feature_engine/imputation/categorical.py @@ -243,9 +243,13 @@ def transform(self, X: pd.DataFrame) -> pd.DataFrame: X = self._transform(X) # if variable is of type category, we need to add the new - # category, before filling in the nan + # category, before filling in the nan, unless it is already + # one of the categories for variable in self.variables_: - if X[variable].dtype.name == "category": + if ( + X[variable].dtype.name == "category" + and self.imputer_dict_[variable] not in X[variable].cat.categories + ): X[variable] = X[variable].cat.add_categories( self.imputer_dict_[variable] ) diff --git a/tests/test_imputation/test_categorical_imputer.py b/tests/test_imputation/test_categorical_imputer.py index 182e8826b..2f4e1bfbc 100644 --- a/tests/test_imputation/test_categorical_imputer.py +++ b/tests/test_imputation/test_categorical_imputer.py @@ -294,6 +294,33 @@ def test_variables_cast_as_category_frequent(df_na): pd.testing.assert_frame_equal(X_transformed, X_reference) +@pytest.mark.parametrize("ordered", [False, True]) +def test_variables_cast_as_category_with_fill_value_already_a_category(ordered): + categories = ["unknown", "west", "east"] + X = pd.DataFrame( + { + "region": pd.Categorical( + ["east", None, "west"], categories=categories, ordered=ordered + ) + } + ) + + imputer = CategoricalImputer(fill_value="unknown", variables=["region"]) + X_transformed = imputer.fit_transform(X) + + X_reference = pd.DataFrame( + { + "region": pd.Categorical( + ["east", "unknown", "west"], categories=categories, ordered=ordered + ) + } + ) + pd.testing.assert_frame_equal(X_transformed, X_reference) + + # transforming the imputed data again leaves it unchanged + pd.testing.assert_frame_equal(imputer.transform(X_transformed), X_reference) + + @pytest.mark.parametrize( "ignore_format", [22.3, 1, "HOLA", {"key1": "value1", "key2": "value2", "key3": "value3"}],