From 3f5ea6d27242d0eabea4d733d2f173c99c11aeec Mon Sep 17 00:00:00 2001 From: Luke Manley Date: Sat, 22 Oct 2022 18:53:16 -0400 Subject: [PATCH 1/3] enforce deprecation of Categorical.replace --- doc/source/whatsnew/v2.0.0.rst | 1 + pandas/core/arrays/categorical.py | 47 ------------------- .../tests/arrays/categorical/test_replace.py | 32 ------------- 3 files changed, 1 insertion(+), 79 deletions(-) diff --git a/doc/source/whatsnew/v2.0.0.rst b/doc/source/whatsnew/v2.0.0.rst index 4ac737bb6b29a..d68a2dd97fb58 100644 --- a/doc/source/whatsnew/v2.0.0.rst +++ b/doc/source/whatsnew/v2.0.0.rst @@ -159,6 +159,7 @@ Removal of prior version deprecations/changes - Removed argument ``try_cast`` from :meth:`DataFrame.mask`, :meth:`DataFrame.where`, :meth:`Series.mask` and :meth:`Series.where` (:issue:`38836`) - Disallow passing non-round floats to :class:`Timestamp` with ``unit="M"`` or ``unit="Y"`` (:issue:`47266`) - Removed deprecated :meth:`Timedelta.delta`, :meth:`Timedelta.is_populated`, and :attr:`Timedelta.freq` (:issue:`46430`, :issue:`46476`) +- Removed deprecated :meth:`Categorical.replace`, use :meth:`Series.replace` instead (:issue:`44929`) - Removed the ``numeric_only`` keyword from :meth:`Categorical.min` and :meth:`Categorical.max` in favor of ``skipna`` (:issue:`48821`) - Removed :func:`is_extension_type` in favor of :func:`is_extension_array_dtype` (:issue:`29457`) - Removed :meth:`Index.get_value` (:issue:`33907`) diff --git a/pandas/core/arrays/categorical.py b/pandas/core/arrays/categorical.py index 5a1d812cda53c..72f7ae6cde989 100644 --- a/pandas/core/arrays/categorical.py +++ b/pandas/core/arrays/categorical.py @@ -2625,53 +2625,6 @@ def isin(self, values) -> npt.NDArray[np.bool_]: code_values = code_values[null_mask | (code_values >= 0)] return algorithms.isin(self.codes, code_values) - @overload - def replace( - self, to_replace, value, *, inplace: Literal[False] = ... - ) -> Categorical: - ... - - @overload - def replace(self, to_replace, value, *, inplace: Literal[True]) -> None: - ... - - @deprecate_nonkeyword_arguments(version=None, allowed_args=["self", "value"]) - def replace(self, to_replace, value, inplace: bool = False) -> Categorical | None: - """ - Replaces all instances of one value with another - - Parameters - ---------- - to_replace: object - The value to be replaced - - value: object - The value to replace it with - - inplace: bool - Whether the operation is done in-place - - Returns - ------- - None if inplace is True, otherwise the new Categorical after replacement - - - Examples - -------- - >>> s = pd.Categorical([1, 2, 1, 3]) - >>> s.replace(1, 3) - [3, 2, 3, 3] - Categories (2, int64): [2, 3] - """ - # GH#44929 deprecation - warn( - "Categorical.replace is deprecated and will be removed in a future " - "version. Use Series.replace directly instead.", - FutureWarning, - stacklevel=find_stack_level(), - ) - return self._replace(to_replace=to_replace, value=value, inplace=inplace) - def _replace(self, *, to_replace, value, inplace: bool = False): inplace = validate_bool_kwarg(inplace, "inplace") cat = self if inplace else self.copy() diff --git a/pandas/tests/arrays/categorical/test_replace.py b/pandas/tests/arrays/categorical/test_replace.py index a50b1eddd99be..bf9409e73f0fe 100644 --- a/pandas/tests/arrays/categorical/test_replace.py +++ b/pandas/tests/arrays/categorical/test_replace.py @@ -1,7 +1,6 @@ import pytest import pandas as pd -from pandas import Categorical import pandas._testing as tm @@ -39,34 +38,3 @@ def test_replace_categorical_series(to_replace, value, expected, flip_categories tm.assert_series_equal(expected, result, check_category_order=False) tm.assert_series_equal(expected, ser, check_category_order=False) - - -@pytest.mark.parametrize( - "to_replace, value, result, expected_error_msg", - [ - ("b", "c", ["a", "c"], "Categorical.categories are different"), - ("c", "d", ["a", "b"], None), - # https://github.com/pandas-dev/pandas/issues/33288 - ("a", "a", ["a", "b"], None), - ("b", None, ["a", None], "Categorical.categories length are different"), - ], -) -def test_replace_categorical(to_replace, value, result, expected_error_msg): - # GH#26988 - cat = Categorical(["a", "b"]) - expected = Categorical(result) - with tm.assert_produces_warning(FutureWarning, match="Series.replace"): - # GH#44929 replace->_replace - result = cat.replace(to_replace, value) - - tm.assert_categorical_equal(result, expected) - if to_replace == "b": # the "c" test is supposed to be unchanged - with pytest.raises(AssertionError, match=expected_error_msg): - # ensure non-inplace call does not affect original - tm.assert_categorical_equal(cat, expected) - - with tm.assert_produces_warning(FutureWarning, match="Series.replace"): - # GH#44929 replace->_replace - cat.replace(to_replace, value, inplace=True) - - tm.assert_categorical_equal(cat, expected) From 6f93671c52473f4a5bcf67f2e4bc3768d9f6f473 Mon Sep 17 00:00:00 2001 From: Luke Manley Date: Sun, 23 Oct 2022 06:52:30 -0400 Subject: [PATCH 2/3] add back test --- .../tests/arrays/categorical/test_replace.py | 27 +++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/pandas/tests/arrays/categorical/test_replace.py b/pandas/tests/arrays/categorical/test_replace.py index bf9409e73f0fe..a3ba420c84a17 100644 --- a/pandas/tests/arrays/categorical/test_replace.py +++ b/pandas/tests/arrays/categorical/test_replace.py @@ -1,6 +1,7 @@ import pytest import pandas as pd +from pandas import Categorical import pandas._testing as tm @@ -38,3 +39,29 @@ def test_replace_categorical_series(to_replace, value, expected, flip_categories tm.assert_series_equal(expected, result, check_category_order=False) tm.assert_series_equal(expected, ser, check_category_order=False) + + +@pytest.mark.parametrize( + "to_replace, value, result, expected_error_msg", + [ + ("b", "c", ["a", "c"], "Categorical.categories are different"), + ("c", "d", ["a", "b"], None), + # https://github.com/pandas-dev/pandas/issues/33288 + ("a", "a", ["a", "b"], None), + ("b", None, ["a", None], "Categorical.categories length are different"), + ], +) +def test_replace_categorical(to_replace, value, result, expected_error_msg): + # GH#26988 + cat = Categorical(["a", "b"]) + expected = Categorical(result) + result = pd.Series(cat).replace(to_replace, value)._values + + tm.assert_categorical_equal(result, expected) + if to_replace == "b": # the "c" test is supposed to be unchanged + with pytest.raises(AssertionError, match=expected_error_msg): + # ensure non-inplace call does not affect original + tm.assert_categorical_equal(cat, expected) + + pd.Series(cat).replace(to_replace, value, inplace=True) + tm.assert_categorical_equal(cat, expected) From c1fb63b6ba8e40bc26cadff097400ad242ec8525 Mon Sep 17 00:00:00 2001 From: Luke Manley Date: Sun, 23 Oct 2022 08:03:33 -0400 Subject: [PATCH 3/3] remove warning from conftest.py --- pandas/conftest.py | 1 - 1 file changed, 1 deletion(-) diff --git a/pandas/conftest.py b/pandas/conftest.py index 074b6068a4518..d9f481d843b37 100644 --- a/pandas/conftest.py +++ b/pandas/conftest.py @@ -154,7 +154,6 @@ def pytest_collection_modifyitems(items, config) -> None: ("DataFrame.append", "The frame.append method is deprecated"), ("Series.append", "The series.append method is deprecated"), ("dtypes.common.is_categorical", "is_categorical is deprecated"), - ("Categorical.replace", "Categorical.replace is deprecated"), ("MultiIndex._is_lexsorted", "MultiIndex.is_lexsorted is deprecated"), # Docstring divides by zero to show behavior difference ("missing.mask_zero_div_zero", "divide by zero encountered"),