Repository: pandas-dev/pandas
Pull request: BUG: preserve name in set_categories (#17509)
- [x] closes #17509
- [x] tests added / passed
- [x] passes `git diff upstream/master -u -- "*.py" | flake8 --diff`
- [x] whatsnew entry


Problem statement:
Series losts its name after set_categories
#### Code Works fine
``` python
(
    Series([1,2,3], name='A')
    .astype('category')
    .name
)
```
I get 'A'

#### Code in trouble
``` python
(
    Series([1,2,3], name='A')
    .astype('category')
    .cat.set_categories([1,2,3])
    .name
)
```
I get NoneType

I think its better to keep original name after set_categories()

Hints from issue discussion:
@jreback : This seems to ring a bell for some reason.  Maybe it was regarding `Series` in general?

In any case, it seems reasonable that the name should be kept.  Feel free to investigate and see where things can be changed to create the desired behavior.
I wonder if https://github.com/pandas-dev/pandas/blob/f11bbf2f505d81900cc83ce387a6a1b1d2a2f866/pandas/core/categorical.py#L2071 should pass through `name=self.name`.
This would affect all of the delegated method:

-  'add_categories',
-  'as_ordered',
-  'as_unordered',
-  'remove_categories',
-  'remove_unused_categories',
-  'rename_categories',
-  'reorder_categories',
- 'set_categories'

@junjiecai mind submitting a pull request with [that change](https://github.com/pandas-dev/pandas/issues/17509#issuecomment-329238872) and a simple test for each of those to verify that the name is passed through?

Commit message: Update test_categorical.py

Patch to review:
diff --git a/doc/source/whatsnew/v0.21.0.txt b/doc/source/whatsnew/v0.21.0.txt
index 52e056103cbdc..eacb51e793bec 100644
--- a/doc/source/whatsnew/v0.21.0.txt
+++ b/doc/source/whatsnew/v0.21.0.txt
@@ -566,7 +566,9 @@ Categorical
 - Bug in the categorical constructor with empty values and categories causing
   the ``.categories`` to be an empty ``Float64Index`` rather than an empty
   ``Index`` with object dtype (:issue:`17248`)
-
+- Bug in categorical operations on Series like `Series.cat.set_categories`
+  not preserving the original Series' name (:issue:`17509`)
+ 
 PyPy
 ^^^^
 
diff --git a/pandas/core/categorical.py b/pandas/core/categorical.py
index e67ce2936819f..ddca93f07ad5e 100644
--- a/pandas/core/categorical.py
+++ b/pandas/core/categorical.py
@@ -2054,9 +2054,10 @@ class CategoricalAccessor(PandasDelegate, NoNewAttributesMixin):
 
     """
 
-    def __init__(self, values, index):
+    def __init__(self, values, index, name):
         self.categorical = values
         self.index = index
+        self.name = name
         self._freeze()
 
     def _delegate_property_get(self, name):
@@ -2075,14 +2076,15 @@ def _delegate_method(self, name, *args, **kwargs):
         method = getattr(self.categorical, name)
         res = method(*args, **kwargs)
         if res is not None:
-            return Series(res, index=self.index)
+            return Series(res, index=self.index, name=self.name)
 
     @classmethod
     def _make_accessor(cls, data):
         if not is_categorical_dtype(data.dtype):
             raise AttributeError("Can only use .cat accessor with a "
                                  "'category' dtype")
-        return CategoricalAccessor(data.values, data.index)
+        return CategoricalAccessor(data.values, data.index,
+                                   getattr(data, 'name', None),)
 
 
 CategoricalAccessor._add_delegate_accessors(delegate=Categorical,
diff --git a/pandas/tests/test_categorical.py b/pandas/tests/test_categorical.py
index 1fa3c84dc0260..89e8ca00a459f 100644
--- a/pandas/tests/test_categorical.py
+++ b/pandas/tests/test_categorical.py
@@ -57,6 +57,13 @@ def test_getitem_listlike(self):
         expected = c[np.array([100000]).astype(np.int64)].codes
         tm.assert_numpy_array_equal(result, expected)
 
+    def test_getname_category(self):
+        expected = 'A'
+        s = pd.Series([1, 2, 3], name='A').astype('category')
+        s = s.cat.set_categories([1, 2, 3])
+        result = s.astype('category').name
+        tm.assert_almost_equal(result, expected)
+
     def test_getitem_category_type(self):
         # GH 14580
         # test iloc() on Series with Categorical data


Code review comments:
diff_hunk: @@ -57,6 +57,13 @@ def test_getitem_listlike(self):
         expected = c[np.array([100000]).astype(np.int64)].codes
         tm.assert_numpy_array_equal(result, expected)
 
+    def test_getname_category(self):
+        expected = 'A'
+        s = pd.Series([1, 2, 3], name='A').astype('category')
+        s = s.cat.set_categories([1, 2, 3])
+        result = s.astype('category').name
path: pandas/tests/test_categorical.py
text: @user1:
This should be `result = s.cat.set_categories([1, 2, 3]).name` so that we're directly testing the behavior that caused the bug.