Skip to content

Commit 26064f0

Browse files
authored
BUG: .cat changing dtype inplace (#43597)
1 parent 72a1090 commit 26064f0

File tree

4 files changed

+51
-3
lines changed

4 files changed

+51
-3
lines changed

doc/source/whatsnew/v1.3.4.rst

+2
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,8 @@ Fixed regressions
1717
- Fixed regression in :meth:`merge` with integer and ``NaN`` keys failing with ``outer`` merge (:issue:`43550`)
1818
- Fixed regression in :meth:`DataFrame.corr` raising ``ValueError`` with ``method="spearman`` on 32-bit platforms (:issue:`43588`)
1919
- Fixed performance regression in :meth:`MultiIndex.equals` (:issue:`43549`)
20+
- Fixed regression in :meth:`Series.cat.reorder_categories` failing to update the categories on the ``Series`` (:issue:`43232`)
21+
- Fixed regression in :meth:`Series.cat.categories` setter failing to update the categories on the ``Series`` (:issue:`43334`)
2022
-
2123

2224
.. ---------------------------------------------------------------------------

pandas/core/arrays/categorical.py

+3-2
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@
5252
cache_readonly,
5353
deprecate_kwarg,
5454
)
55+
from pandas.util._exceptions import find_stack_level
5556
from pandas.util._validators import validate_bool_kwarg
5657

5758
from pandas.core.dtypes.cast import (
@@ -1116,10 +1117,10 @@ def reorder_categories(self, new_categories, ordered=None, inplace=no_default):
11161117
warn(
11171118
"The `inplace` parameter in pandas.Categorical."
11181119
"reorder_categories is deprecated and will be removed in "
1119-
"a future version. Removing unused categories will always "
1120+
"a future version. Reordering categories will always "
11201121
"return a new Categorical object.",
11211122
FutureWarning,
1122-
stacklevel=2,
1123+
stacklevel=find_stack_level(),
11231124
)
11241125
else:
11251126
inplace = False

pandas/core/internals/blocks.py

+6-1
Original file line numberDiff line numberDiff line change
@@ -336,7 +336,6 @@ def getitem_block_columns(self, slicer, new_mgr_locs: BlockPlacement) -> Block:
336336
def shape(self) -> Shape:
337337
return self.values.shape
338338

339-
@final
340339
@cache_readonly
341340
def dtype(self) -> DtypeObj:
342341
return self.values.dtype
@@ -1881,6 +1880,12 @@ class CategoricalBlock(ExtensionBlock):
18811880
# this Block type is kept for backwards-compatibility
18821881
__slots__ = ()
18831882

1883+
# GH#43232, GH#43334 self.values.dtype can be changed inplace until 2.0,
1884+
# so this cannot be cached
1885+
@property
1886+
def dtype(self) -> DtypeObj:
1887+
return self.values.dtype
1888+
18841889

18851890
# -----------------------------------------------------------------
18861891
# Constructor Helpers

pandas/tests/series/accessors/test_cat_accessor.py

+40
Original file line numberDiff line numberDiff line change
@@ -249,3 +249,43 @@ def test_dt_accessor_api_for_categorical(self):
249249
with pytest.raises(AttributeError, match=msg):
250250
invalid.dt
251251
assert not hasattr(invalid, "str")
252+
253+
def test_reorder_categories_updates_dtype(self):
254+
# GH#43232
255+
ser = Series(["a", "b", "c"], dtype="category")
256+
orig_dtype = ser.dtype
257+
258+
# Need to construct this before calling reorder_categories inplace
259+
expected = ser.cat.reorder_categories(["c", "b", "a"])
260+
261+
with tm.assert_produces_warning(FutureWarning, match="`inplace` parameter"):
262+
ser.cat.reorder_categories(["c", "b", "a"], inplace=True)
263+
264+
assert not orig_dtype.categories.equals(ser.dtype.categories)
265+
assert not orig_dtype.categories.equals(expected.dtype.categories)
266+
assert ser.dtype == expected.dtype
267+
assert ser.dtype.categories.equals(expected.dtype.categories)
268+
269+
tm.assert_series_equal(ser, expected)
270+
271+
def test_set_categories_setitem(self):
272+
# GH#43334
273+
274+
df = DataFrame({"Survived": [1, 0, 1], "Sex": [0, 1, 1]}, dtype="category")
275+
276+
# change the dtype in-place
277+
df["Survived"].cat.categories = ["No", "Yes"]
278+
df["Sex"].cat.categories = ["female", "male"]
279+
280+
# values should not be coerced to NaN
281+
assert list(df["Sex"]) == ["female", "male", "male"]
282+
assert list(df["Survived"]) == ["Yes", "No", "Yes"]
283+
284+
df["Sex"] = Categorical(df["Sex"], categories=["female", "male"], ordered=False)
285+
df["Survived"] = Categorical(
286+
df["Survived"], categories=["No", "Yes"], ordered=False
287+
)
288+
289+
# values should not be coerced to NaN
290+
assert list(df["Sex"]) == ["female", "male", "male"]
291+
assert list(df["Survived"]) == ["Yes", "No", "Yes"]

0 commit comments

Comments
 (0)