diff --git a/pandas/core/indexes/base.py b/pandas/core/indexes/base.py index bfa669a0ca164..7237b7754b09e 100644 --- a/pandas/core/indexes/base.py +++ b/pandas/core/indexes/base.py @@ -1278,39 +1278,52 @@ def _set_names(self, values, level=None): def set_names(self, names, level=None, inplace=False): """ - Set new names on index. Defaults to returning new index. + Set Index or MultiIndex name. + + Able to set new names partially and by level. Parameters ---------- - names : str or sequence - name(s) to set - level : int, level name, or sequence of int/level names (default None) - If the index is a MultiIndex (hierarchical), level(s) to set (None - for all levels). Otherwise level must be None - inplace : bool - if True, mutates in place + names : label or list of label + Name(s) to set. + level : int, label or list of int or label, optional + If the index is a MultiIndex, level(s) to set (None for all + levels). Otherwise level must be None. + inplace : bool, default False + Modifies the object directly, instead of creating a new Index or + MultiIndex. Returns ------- - new index (of same type and class...etc) [if inplace, returns None] + Index + The same type as the caller or None if inplace is True. + + See Also + -------- + Index.rename : Able to set new names without level. Examples -------- - >>> pd.Index([1, 2, 3, 4]).set_names('foo') - Int64Index([1, 2, 3, 4], dtype='int64', name='foo') - >>> pd.Index([1, 2, 3, 4]).set_names(['foo']) - Int64Index([1, 2, 3, 4], dtype='int64', name='foo') - >>> idx = pd.MultiIndex.from_tuples([(1, u'one'), (1, u'two'), - (2, u'one'), (2, u'two')], - names=['foo', 'bar']) - >>> idx.set_names(['baz', 'quz']) - MultiIndex(levels=[[1, 2], [u'one', u'two']], - labels=[[0, 0, 1, 1], [0, 1, 0, 1]], - names=[u'baz', u'quz']) - >>> idx.set_names('baz', level=0) - MultiIndex(levels=[[1, 2], [u'one', u'two']], - labels=[[0, 0, 1, 1], [0, 1, 0, 1]], - names=[u'baz', u'bar']) + >>> idx = pd.Index([1, 2, 3, 4]) + >>> idx + Int64Index([1, 2, 3, 4], dtype='int64') + >>> idx.set_names('quarter') + Int64Index([1, 2, 3, 4], dtype='int64', name='quarter') + + >>> idx = pd.MultiIndex.from_product([['python', 'cobra'], + ... [2018, 2019]]) + >>> idx + MultiIndex(levels=[['cobra', 'python'], [2018, 2019]], + labels=[[1, 1, 0, 0], [0, 1, 0, 1]]) + >>> idx.set_names(['kind', 'year'], inplace=True) + >>> idx + MultiIndex(levels=[['cobra', 'python'], [2018, 2019]], + labels=[[1, 1, 0, 0], [0, 1, 0, 1]], + names=['kind', 'year']) + >>> idx.set_names('species', level=0) + MultiIndex(levels=[['cobra', 'python'], [2018, 2019]], + labels=[[1, 1, 0, 0], [0, 1, 0, 1]], + names=['species', 'year']) """ from .multi import MultiIndex @@ -1319,7 +1332,8 @@ def set_names(self, names, level=None, inplace=False): if level is not None and not is_list_like(level) and is_list_like( names): - raise TypeError("Names must be a string") + msg = "Names must be a string when a single level is provided." + raise TypeError(msg) if not is_list_like(names) and level is None and self.nlevels > 1: raise TypeError("Must pass list-like as `names`.") @@ -1339,18 +1353,48 @@ def set_names(self, names, level=None, inplace=False): def rename(self, name, inplace=False): """ - Set new names on index. Defaults to returning new index. + Alter Index or MultiIndex name. + + Able to set new names without level. Defaults to returning new index. + Length of names must match number of levels in MultiIndex. Parameters ---------- - name : str or list - name to set - inplace : bool - if True, mutates in place + name : label or list of labels + Name(s) to set. + inplace : boolean, default False + Modifies the object directly, instead of creating a new Index or + MultiIndex. Returns ------- - new index (of same type and class...etc) [if inplace, returns None] + Index + The same type as the caller or None if inplace is True. + + See Also + -------- + Index.set_names : Able to set new names partially and by level. + + Examples + -------- + >>> idx = pd.Index(['A', 'C', 'A', 'B'], name='score') + >>> idx.rename('grade') + Index(['A', 'C', 'A', 'B'], dtype='object', name='grade') + + >>> idx = pd.MultiIndex.from_product([['python', 'cobra'], + ... [2018, 2019]], + ... names=['kind', 'year']) + >>> idx + MultiIndex(levels=[['cobra', 'python'], [2018, 2019]], + labels=[[1, 1, 0, 0], [0, 1, 0, 1]], + names=['kind', 'year']) + >>> idx.rename(['species', 'year']) + MultiIndex(levels=[['cobra', 'python'], [2018, 2019]], + labels=[[1, 1, 0, 0], [0, 1, 0, 1]], + names=['species', 'year']) + >>> idx.rename('species') + Traceback (most recent call last): + TypeError: Must pass list-like as `names`. """ return self.set_names([name], inplace=inplace) diff --git a/pandas/tests/indexes/multi/test_get_set.py b/pandas/tests/indexes/multi/test_get_set.py index 30be5b546f7c7..99ab54a83636c 100644 --- a/pandas/tests/indexes/multi/test_get_set.py +++ b/pandas/tests/indexes/multi/test_get_set.py @@ -360,7 +360,7 @@ def test_set_levels_labels_names_bad_input(idx): with tm.assert_raises_regex(ValueError, 'Length of names'): idx.set_names(names[0], level=[0, 1]) - with tm.assert_raises_regex(TypeError, 'string'): + with tm.assert_raises_regex(TypeError, 'Names must be a'): idx.set_names(names, level=0)