From 10ea582b19d1bf7bf0bc0976a08e3a57106aea1d Mon Sep 17 00:00:00 2001 From: Tom Augspurger Date: Mon, 14 Mar 2016 16:38:28 -0500 Subject: [PATCH] BUG: .rename* not treating Series as mapping Closes https://github.com/pydata/pandas/issues/12623 I added com.is_dict_like in https://github.com/pydata/pandas/pull/11980 and failed to use it for the `rename` method. Using that now and did some refactoring while I was in there. Added more tests for rename. --- doc/source/whatsnew/v0.18.1.txt | 5 +++ pandas/core/generic.py | 9 ++--- pandas/core/series.py | 9 ++--- pandas/tests/series/test_alter_axes.py | 7 ++++ pandas/tests/test_generic.py | 50 +++++++++++++++++++++----- 5 files changed, 59 insertions(+), 21 deletions(-) diff --git a/doc/source/whatsnew/v0.18.1.txt b/doc/source/whatsnew/v0.18.1.txt index dbe446f0a7b4f..76d86847d3f2c 100644 --- a/doc/source/whatsnew/v0.18.1.txt +++ b/doc/source/whatsnew/v0.18.1.txt @@ -89,3 +89,8 @@ Bug Fixes ~~~~~~~~~ - Bug in ``value_counts`` when ``normalize=True`` and ``dropna=True`` where nulls still contributed to the normalized count (:issue:`12558`) + + +- Bug in ``Series.rename``, ``DataFrame.rename`` and ``DataFrame.rename_axis`` not treating ``Series`` as mappings to relabel (:issue:`12623`). + + diff --git a/pandas/core/generic.py b/pandas/core/generic.py index 963c953154b57..4d62002134eb1 100644 --- a/pandas/core/generic.py +++ b/pandas/core/generic.py @@ -700,12 +700,9 @@ def rename_axis(self, mapper, axis=0, copy=True, inplace=False): 1 2 5 2 3 6 """ - is_scalar_or_list = ( - (not com.is_sequence(mapper) and not callable(mapper)) or - (com.is_list_like(mapper) and not com.is_dict_like(mapper)) - ) - - if is_scalar_or_list: + non_mapper = lib.isscalar(mapper) or (com.is_list_like(mapper) and not + com.is_dict_like(mapper)) + if non_mapper: return self._set_axis_name(mapper, axis=axis) else: axis = self._get_axis_name(axis) diff --git a/pandas/core/series.py b/pandas/core/series.py index d339a93a3ed9b..398c62467424b 100644 --- a/pandas/core/series.py +++ b/pandas/core/series.py @@ -8,7 +8,6 @@ import types import warnings -from collections import MutableMapping from numpy import nan, ndarray import numpy as np @@ -2331,11 +2330,9 @@ def align(self, other, join='outer', axis=None, level=None, copy=True, @Appender(generic._shared_docs['rename'] % _shared_doc_kwargs) def rename(self, index=None, **kwargs): - is_scalar_or_list = ( - (not com.is_sequence(index) and not callable(index)) or - (com.is_list_like(index) and not isinstance(index, MutableMapping)) - ) - if is_scalar_or_list: + non_mapping = lib.isscalar(index) or (com.is_list_like(index) and + not com.is_dict_like(index)) + if non_mapping: return self._set_name(index, inplace=kwargs.get('inplace')) return super(Series, self).rename(index=index, **kwargs) diff --git a/pandas/tests/series/test_alter_axes.py b/pandas/tests/series/test_alter_axes.py index 0bbb96d3e1d5d..4f9a55908fe96 100644 --- a/pandas/tests/series/test_alter_axes.py +++ b/pandas/tests/series/test_alter_axes.py @@ -55,6 +55,13 @@ def test_rename(self): renamed = renamer.rename({}) self.assertEqual(renamed.index.name, renamer.index.name) + def test_rename_by_series(self): + s = Series(range(5), name='foo') + renamer = Series({1: 10, 2: 20}) + result = s.rename(renamer) + expected = Series(range(5), index=[0, 10, 20, 3, 4], name='foo') + tm.assert_series_equal(result, expected) + def test_rename_set_name(self): s = Series(range(4), index=list('abcd')) for name in ['foo', ['foo'], ('foo',)]: diff --git a/pandas/tests/test_generic.py b/pandas/tests/test_generic.py index 1198d6b194c60..68cc74e010781 100644 --- a/pandas/tests/test_generic.py +++ b/pandas/tests/test_generic.py @@ -88,21 +88,53 @@ def _compare(self, result, expected): def test_rename(self): # single axis + idx = list('ABCD') + # relabeling values passed into self.rename + args = [ + str.lower, + {x: x.lower() for x in idx}, + Series({x: x.lower() for x in idx}), + ] + for axis in self._axes(): - kwargs = {axis: list('ABCD')} + kwargs = {axis: idx} obj = self._construct(4, **kwargs) - # no values passed - # self.assertRaises(Exception, o.rename(str.lower)) - - # rename a single axis - result = obj.rename(**{axis: str.lower}) - expected = obj.copy() - setattr(expected, axis, list('abcd')) - self._compare(result, expected) + for arg in args: + # rename a single axis + result = obj.rename(**{axis: arg}) + expected = obj.copy() + setattr(expected, axis, list('abcd')) + self._compare(result, expected) # multiple axes at once + def test_rename_axis(self): + idx = list('ABCD') + # relabeling values passed into self.rename + args = [ + str.lower, + {x: x.lower() for x in idx}, + Series({x: x.lower() for x in idx}), + ] + + for axis in self._axes(): + kwargs = {axis: idx} + obj = self._construct(4, **kwargs) + + for arg in args: + # rename a single axis + result = obj.rename_axis(arg, axis=axis) + expected = obj.copy() + setattr(expected, axis, list('abcd')) + self._compare(result, expected) + # scalar values + for arg in ['foo', None]: + result = obj.rename_axis(arg, axis=axis) + expected = obj.copy() + getattr(expected, axis).name = arg + self._compare(result, expected) + def test_get_numeric_data(self): n = 4