From 6c751c0f67bd1da8ca42568432c65383c99a9230 Mon Sep 17 00:00:00 2001 From: Ghasem Naddaf <> Date: Tue, 14 Nov 2017 16:32:47 -0800 Subject: [PATCH 1/2] BUG: Copy categorical codes if empty (fixes #18051) rebased to remove conflicts in whats new --- doc/source/whatsnew/v0.21.1.txt | 1 + pandas/core/categorical.py | 2 +- pandas/tests/test_categorical.py | 4 ++++ 3 files changed, 6 insertions(+), 1 deletion(-) diff --git a/doc/source/whatsnew/v0.21.1.txt b/doc/source/whatsnew/v0.21.1.txt index 0ab536f2898c7..7a5ccc6fa7853 100644 --- a/doc/source/whatsnew/v0.21.1.txt +++ b/doc/source/whatsnew/v0.21.1.txt @@ -130,6 +130,7 @@ Categorical - Error messages in the testing module have been improved when items have different ``CategoricalDtype`` (:issue:`18069`) - ``CategoricalIndex`` can now correctly take a ``pd.api.types.CategoricalDtype`` as its dtype (:issue:`18116`) +- Bug in ``Categorical.unique()`` returning read-only ``codes`` array when all categories were ``NaN`` (:issue:`18051`) Other ^^^^^ diff --git a/pandas/core/categorical.py b/pandas/core/categorical.py index 6d60cf72efd62..645921bb007a1 100644 --- a/pandas/core/categorical.py +++ b/pandas/core/categorical.py @@ -2250,7 +2250,7 @@ def _recode_for_categories(codes, old_categories, new_categories): if len(old_categories) == 0: # All null anyway, so just retain the nulls - return codes + return codes.copy() indexer = coerce_indexer_dtype(new_categories.get_indexer(old_categories), new_categories) new_codes = take_1d(indexer, codes.copy(), fill_value=-1) diff --git a/pandas/tests/test_categorical.py b/pandas/tests/test_categorical.py index f062da02b2493..f593ba85aec5f 100644 --- a/pandas/tests/test_categorical.py +++ b/pandas/tests/test_categorical.py @@ -1673,6 +1673,10 @@ def test_unique(self): exp_cat = Categorical(["b", np.nan, "a"], categories=["b", "a"]) tm.assert_categorical_equal(res, exp_cat) + # GH 18051 unique()._codes should be writeable + cat_nan = Categorical([np.nan]) + assert cat_nan.unique()._codes.flags.writeable + def test_unique_ordered(self): # keep categories order when ordered=True cat = Categorical(['b', 'a', 'b'], categories=['a', 'b'], ordered=True) From 21734aaf459212dce9a1de0f1e2a62527ba4e659 Mon Sep 17 00:00:00 2001 From: Ghasem Naddaf <> Date: Mon, 20 Nov 2017 12:44:57 -0800 Subject: [PATCH 2/2] Unit tests --- pandas/tests/test_categorical.py | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/pandas/tests/test_categorical.py b/pandas/tests/test_categorical.py index f593ba85aec5f..5fbf1679b7ad1 100644 --- a/pandas/tests/test_categorical.py +++ b/pandas/tests/test_categorical.py @@ -1673,9 +1673,11 @@ def test_unique(self): exp_cat = Categorical(["b", np.nan, "a"], categories=["b", "a"]) tm.assert_categorical_equal(res, exp_cat) - # GH 18051 unique()._codes should be writeable - cat_nan = Categorical([np.nan]) - assert cat_nan.unique()._codes.flags.writeable + # GH 18051 + cat = Categorical([np.nan]) + res = cat.unique() + exp_cat = Categorical([np.nan], categories=[]) + tm.assert_categorical_equal(res, exp_cat) def test_unique_ordered(self): # keep categories order when ordered=True @@ -2178,6 +2180,10 @@ def test_basic(self): result = x.person_name.loc[0] assert result == expected + # GH 18051 + s = pd.Series(pd.Categorical([np.nan])) + assert s.nunique() == 0 + def test_creation_astype(self): l = ["a", "b", "c", "a"] s = pd.Series(l)