From bb12644328b3c58be26549f54a4ad15e4b0e58f6 Mon Sep 17 00:00:00 2001 From: Dr-Irv Date: Wed, 7 Mar 2018 10:01:58 -0500 Subject: [PATCH 01/12] First version --- pandas/core/generic.py | 49 ++++++++++++---------- pandas/tests/frame/test_alter_axes.py | 59 ++++++++++++++++++--------- pandas/tests/io/test_pytables.py | 4 +- pandas/tests/reshape/test_concat.py | 9 ++-- pandas/tests/test_panel.py | 6 +-- 5 files changed, 76 insertions(+), 51 deletions(-) diff --git a/pandas/core/generic.py b/pandas/core/generic.py index a45887543dc53..b65f8e91e344e 100644 --- a/pandas/core/generic.py +++ b/pandas/core/generic.py @@ -748,6 +748,20 @@ def swaplevel(self, i=-2, j=-1, axis=0): # ---------------------------------------------------------------------- # Rename + + # renamer function if passed a dict + def _get_rename_function(mapper): + if isinstance(mapper, (dict, ABCSeries)): + + def f(x): + if x in mapper: + return mapper[x] + else: + return x + else: + f = mapper + + return f # TODO: define separate funcs for DataFrame, Series and Panel so you can # get completion on keyword arguments. @@ -874,20 +888,6 @@ def rename(self, *args, **kwargs): if com._count_not_none(*axes.values()) == 0: raise TypeError('must pass an index to rename') - # renamer function if passed a dict - def _get_rename_function(mapper): - if isinstance(mapper, (dict, ABCSeries)): - - def f(x): - if x in mapper: - return mapper[x] - else: - return x - else: - f = mapper - - return f - self._consolidate_inplace() result = self if inplace else self.copy(deep=copy) @@ -896,7 +896,7 @@ def f(x): v = axes.get(self._AXIS_NAMES[axis]) if v is None: continue - f = _get_rename_function(v) + f = self._get_rename_function(v) baxis = self._get_block_manager_axis(axis) if level is not None: @@ -964,13 +964,18 @@ def rename_axis(self, mapper, axis=0, copy=True, inplace=False): if non_mapper: return self._set_axis_name(mapper, axis=axis, inplace=inplace) else: - msg = ("Using 'rename_axis' to alter labels is deprecated. " - "Use '.rename' instead") - warnings.warn(msg, FutureWarning, stacklevel=2) - axis = self._get_axis_name(axis) - d = {'copy': copy, 'inplace': inplace} - d[axis] = mapper - return self.rename(**d) +# msg = ("Using 'rename_axis' to alter labels is deprecated. " +# "Use '.rename' instead") +# warnings.warn(msg, FutureWarning, stacklevel=2) +# axis = self._get_axis_name(axis) +# d = {'copy': copy, 'inplace': inplace} +# d[axis] = mapper +# return self.rename(**d) + f = self._get_rename_function(mapper) + curnames = self._get_axis(axis).names + newnames = [f(name) for name in curnames] + return self._set_axis_name(newnames, axis=axis, inplace=inplace) + def _set_axis_name(self, name, axis=0, inplace=False): """ diff --git a/pandas/tests/frame/test_alter_axes.py b/pandas/tests/frame/test_alter_axes.py index c824f0026af50..9faad2baaf84d 100644 --- a/pandas/tests/frame/test_alter_axes.py +++ b/pandas/tests/frame/test_alter_axes.py @@ -451,25 +451,46 @@ def test_rename_axis_inplace(self): assert no_return is None assert_frame_equal(result, expected) - def test_rename_axis_warns(self): - # https://github.com/pandas-dev/pandas/issues/17833 - df = pd.DataFrame({"A": [1, 2], "B": [1, 2]}) - with tm.assert_produces_warning(FutureWarning) as w: - df.rename_axis(id, axis=0) - assert 'rename' in str(w[0].message) - - with tm.assert_produces_warning(FutureWarning) as w: - df.rename_axis({0: 10, 1: 20}, axis=0) - assert 'rename' in str(w[0].message) - - with tm.assert_produces_warning(FutureWarning) as w: - df.rename_axis(id, axis=1) - assert 'rename' in str(w[0].message) - - with tm.assert_produces_warning(FutureWarning) as w: - df['A'].rename_axis(id) - assert 'rename' in str(w[0].message) - +# def test_rename_axis_warns(self): +# # https://github.com/pandas-dev/pandas/issues/17833 +# df = pd.DataFrame({"A": [1, 2], "B": [1, 2]}) +# with tm.assert_produces_warning(FutureWarning) as w: +# df.rename_axis(id, axis=0) +# assert 'rename' in str(w[0].message) +# +# with tm.assert_produces_warning(FutureWarning) as w: +# df.rename_axis({0: 10, 1: 20}, axis=0) +# assert 'rename' in str(w[0].message) +# +# with tm.assert_produces_warning(FutureWarning) as w: +# df.rename_axis(id, axis=1) +# assert 'rename' in str(w[0].message) +# +# with tm.assert_produces_warning(FutureWarning) as w: +# df['A'].rename_axis(id) +# assert 'rename' in str(w[0].message) + + def test_rename_axis_mapper(self): + mi = pd.MultiIndex.from_product([['a', 'b', 'c'], [1, 2]], + names=['ll', 'nn']) + + df = pd.DataFrame({'x': [i for i in range(len(mi))], + 'y' : [i*10 for i in range(len(mi))]}, + index=mi) + result = df.rename_axis('cols', axis=1) + tm.assert_index_equal(result.columns, + pd.Index(['x', 'y'], name='cols')) + + result = result.rename_axis({'cols' : 'new'}, axis=1) + tm.assert_index_equal(result.columns, + pd.Index(['x', 'y'], name='new')) + + result = df.rename_axis({'ll' : 'foo'}) + assert result.index.names == ['foo', 'nn'] + + result = df.rename_axis(str.upper, axis=0) + assert result.index.names == ['LL', 'NN'] + def test_rename_multiindex(self): tuples_index = [('foo1', 'bar1'), ('foo2', 'bar2')] diff --git a/pandas/tests/io/test_pytables.py b/pandas/tests/io/test_pytables.py index e690b1e302d8b..b3e2a5bf008ce 100644 --- a/pandas/tests/io/test_pytables.py +++ b/pandas/tests/io/test_pytables.py @@ -1288,8 +1288,8 @@ def test_append_with_strings(self): with ensure_clean_store(self.path) as store: with catch_warnings(record=True): wp = tm.makePanel() - wp2 = wp.rename_axis( - {x: "%s_extra" % x for x in wp.minor_axis}, axis=2) + wp2 = wp.rename( + minor_axis = {x: "%s_extra" % x for x in wp.minor_axis}) def check_col(key, name, size): assert getattr(store.get_storer(key) diff --git a/pandas/tests/reshape/test_concat.py b/pandas/tests/reshape/test_concat.py index 437b4179c580a..b20a2ce99b3c2 100644 --- a/pandas/tests/reshape/test_concat.py +++ b/pandas/tests/reshape/test_concat.py @@ -1401,12 +1401,11 @@ def df(): panel1 = make_panel() panel2 = make_panel() - panel2 = panel2.rename_axis(dict((x, "%s_1" % x) - for x in panel2.major_axis), - axis=1) + panel2 = panel2.rename(major_axis=dict((x, "%s_1" % x) + for x in panel2.major_axis)) - panel3 = panel2.rename_axis(lambda x: '%s_1' % x, axis=1) - panel3 = panel3.rename_axis(lambda x: '%s_1' % x, axis=2) + panel3 = panel2.rename(major_axis=lambda x: '%s_1' % x) + panel3 = panel3.rename(minor_axis=lambda x: '%s_1' % x) # it works! concat([panel1, panel3], axis=1, verify_integrity=True) diff --git a/pandas/tests/test_panel.py b/pandas/tests/test_panel.py index 301a7fc437fcf..49ae4a19a4bbd 100644 --- a/pandas/tests/test_panel.py +++ b/pandas/tests/test_panel.py @@ -2176,16 +2176,16 @@ def test_rename(self): with catch_warnings(record=True): mapper = {'ItemA': 'foo', 'ItemB': 'bar', 'ItemC': 'baz'} - renamed = self.panel.rename_axis(mapper, axis=0) + renamed = self.panel.rename(items=mapper) exp = Index(['foo', 'bar', 'baz']) tm.assert_index_equal(renamed.items, exp) - renamed = self.panel.rename_axis(str.lower, axis=2) + renamed = self.panel.rename(minor_axis=str.lower) exp = Index(['a', 'b', 'c', 'd']) tm.assert_index_equal(renamed.minor_axis, exp) # don't copy - renamed_nocopy = self.panel.rename_axis(mapper, axis=0, copy=False) + renamed_nocopy = self.panel.rename(items=mapper, copy=False) renamed_nocopy['foo'] = 3. assert (self.panel['ItemA'].values == 3).all() From 99011df0cc42d1649aaee3a44eb534dde2bc6288 Mon Sep 17 00:00:00 2001 From: Dr-Irv Date: Wed, 7 Mar 2018 14:11:00 -0500 Subject: [PATCH 02/12] some doc changes --- pandas/core/generic.py | 41 +++++++++++++++++++++++++++++++---------- 1 file changed, 31 insertions(+), 10 deletions(-) diff --git a/pandas/core/generic.py b/pandas/core/generic.py index b65f8e91e344e..8a8cc8121c19c 100644 --- a/pandas/core/generic.py +++ b/pandas/core/generic.py @@ -913,12 +913,16 @@ def rename(self, *args, **kwargs): rename.__doc__ = _shared_docs['rename'] def rename_axis(self, mapper, axis=0, copy=True, inplace=False): - """Alter the name of the index or columns. + """Alter the name of the index or name of index backing the + columns. Parameters ---------- - mapper : scalar, list-like, optional - Value to set the axis name attribute. + s, index, columns : dict-like or function, optional + dict-like or functions transformations to apply to + that axis' values. Use either ``s`` and ``axis`` to + specify the axis to target with ``s``, or ``index`` and + ``columns``. axis : int or string, default 0 copy : boolean, default True Also copy underlying data @@ -934,6 +938,22 @@ def rename_axis(self, mapper, axis=0, copy=True, inplace=False): the axis *labels* by passing a mapping or scalar. This behavior is deprecated and will be removed in a future version. Use ``rename`` instead. + + ``DataFrame.rename_axis`` supports two calling conventions + + * ``(index=index_mapper, columns=columns_mapper, ...)`` + * ``(s, axis={'index', 'columns'}, ...)`` + + The first calling convention will only modify the names of + the index or the names of the index backing the columns. + + The second calling convention will modify the names of the + the corresponding index if s is a list or a scalar. + However, if s is dict-like or a function, it will use the + deprecated behavior of modifying the axis *labels*. + + We *highly* recommend using keyword arguments to clarify your + intent. See Also -------- @@ -964,13 +984,14 @@ def rename_axis(self, mapper, axis=0, copy=True, inplace=False): if non_mapper: return self._set_axis_name(mapper, axis=axis, inplace=inplace) else: -# msg = ("Using 'rename_axis' to alter labels is deprecated. " -# "Use '.rename' instead") -# warnings.warn(msg, FutureWarning, stacklevel=2) -# axis = self._get_axis_name(axis) -# d = {'copy': copy, 'inplace': inplace} -# d[axis] = mapper -# return self.rename(**d) + msg = ("Using 'rename_axis' to alter labels is deprecated. " + "Use '.rename' instead") + warnings.warn(msg, FutureWarning, stacklevel=2) + axis = self._get_axis_name(axis) + d = {'copy': copy, 'inplace': inplace} + d[axis] = mapper + return self.rename(**d) + if (FALSE): f = self._get_rename_function(mapper) curnames = self._get_axis(axis).names newnames = [f(name) for name in curnames] From 4b45493223778a89eee0f0bfc6540cbc54cb793d Mon Sep 17 00:00:00 2001 From: Dr-Irv Date: Wed, 7 Mar 2018 15:36:21 -0500 Subject: [PATCH 03/12] full implementation --- pandas/core/generic.py | 66 ++++++++++++++++++++++++++++-------------- 1 file changed, 45 insertions(+), 21 deletions(-) diff --git a/pandas/core/generic.py b/pandas/core/generic.py index 8a8cc8121c19c..ae16bae6d7abe 100644 --- a/pandas/core/generic.py +++ b/pandas/core/generic.py @@ -912,7 +912,7 @@ def rename(self, *args, **kwargs): rename.__doc__ = _shared_docs['rename'] - def rename_axis(self, mapper, axis=0, copy=True, inplace=False): + def rename_axis(self, s=None, **kwargs): """Alter the name of the index or name of index backing the columns. @@ -921,8 +921,8 @@ def rename_axis(self, mapper, axis=0, copy=True, inplace=False): s, index, columns : dict-like or function, optional dict-like or functions transformations to apply to that axis' values. Use either ``s`` and ``axis`` to - specify the axis to target with ``s``, or ``index`` and - ``columns``. + specify the axis to target with ``s``, or ``index`` + and/or ``columns``. axis : int or string, default 0 copy : boolean, default True Also copy underlying data @@ -945,7 +945,8 @@ def rename_axis(self, mapper, axis=0, copy=True, inplace=False): * ``(s, axis={'index', 'columns'}, ...)`` The first calling convention will only modify the names of - the index or the names of the index backing the columns. + the index and/or the names of the index backing the columns. + In this case, the parameter ``copy`` is ignored. The second calling convention will modify the names of the the corresponding index if s is a list or a scalar. @@ -978,25 +979,48 @@ def rename_axis(self, mapper, axis=0, copy=True, inplace=False): 2 3 6 """ + axes, kwargs = self._construct_axes_from_arguments((), kwargs) + copy = kwargs.pop('copy', True) + inplace = kwargs.pop('inplace', False) + axis = kwargs.pop('axis', None) + if axis is not None: + axis = self._get_axis_number(axis) + + if kwargs: + raise TypeError('rename_axis() got an unexpected keyword ' + 'argument "{0}"'.format(list(kwargs.keys())[0])) inplace = validate_bool_kwarg(inplace, 'inplace') - non_mapper = is_scalar(mapper) or (is_list_like(mapper) and not - is_dict_like(mapper)) - if non_mapper: - return self._set_axis_name(mapper, axis=axis, inplace=inplace) + + if (s is not None): + # Use old behavior if a scalar or list + non_mapper = is_scalar(s) or (is_list_like(s) and not + is_dict_like(s)) + if non_mapper: + return self._set_axis_name(s, axis=axis, inplace=inplace) + else: + msg = ("Using 'rename_axis' to alter labels is deprecated. " + "Use '.rename' instead") + warnings.warn(msg, FutureWarning, stacklevel=2) + axis = self._get_axis_name(axis) + d = {'copy': copy, 'inplace': inplace} + d[axis] = s + return self.rename(**d) else: - msg = ("Using 'rename_axis' to alter labels is deprecated. " - "Use '.rename' instead") - warnings.warn(msg, FutureWarning, stacklevel=2) - axis = self._get_axis_name(axis) - d = {'copy': copy, 'inplace': inplace} - d[axis] = mapper - return self.rename(**d) - if (FALSE): - f = self._get_rename_function(mapper) - curnames = self._get_axis(axis).names - newnames = [f(name) for name in curnames] - return self._set_axis_name(newnames, axis=axis, inplace=inplace) - + # Use new behavior. Means that index and/or columns + # is specified + result = self if inplace else self.copy(deep=copy) + + for axis in lrange(self._AXIS_LEN): + v = axes.get(self._AXIS_NAMES[axis]) + if v is None: + continue + f = self._get_rename_function(v) + curnames = self._get_axis(axis).names + newnames = [f(name) for name in curnames] + result._set_axis_name(newnames, axis=axis, + inplace=True) + if not inplace: + return result def _set_axis_name(self, name, axis=0, inplace=False): """ From 5ff65a65a82f7bfc791c11fc6b74d8437f2f7b71 Mon Sep 17 00:00:00 2001 From: Dr-Irv Date: Wed, 7 Mar 2018 18:16:48 -0500 Subject: [PATCH 04/12] First test of new rename_axis --- doc/source/basics.rst | 19 +++++- doc/source/whatsnew/v0.23.0.txt | 1 + pandas/core/generic.py | 95 +++++++++++++++++++------- pandas/tests/frame/test_alter_axes.py | 87 +++++++++++++---------- pandas/tests/io/test_pytables.py | 2 +- pandas/tests/reshape/test_concat.py | 2 +- pandas/tests/series/test_alter_axes.py | 18 +++++ 7 files changed, 161 insertions(+), 63 deletions(-) diff --git a/doc/source/basics.rst b/doc/source/basics.rst index 8d09f1fc04c1f..08b7a0b5a3938 100644 --- a/doc/source/basics.rst +++ b/doc/source/basics.rst @@ -1465,10 +1465,25 @@ for altering the ``Series.name`` attribute. s.rename("scalar-name") +The Panel class has a related :meth:`~Panel.rename` class which can rename +any of its three axes. + .. _basics.rename_axis: -The Panel class has a related :meth:`~Panel.rename_axis` class which can rename -any of its three axes. +.. versionadded:: 0.23.0 + +The methods :meth:`~DataFrame.rename_axis` and :meth:`~Series.rename_axis` +allow specific names of a `MultiIndex` to be changed (as opposed to the +labels). + +.. ipython:: python + + df = pd.DataFrame({'x': [1,2,3,4,5,6], 'y': [10,20,30,40,50,60]}, + index=pd.MultiIndex.from_product([['a','b','c'],[1,2]], + names=['let','num'])) + df + df.rename_axis(index={'let': 'abc'}) + df.rename_axis(index=str.upper) .. _basics.iteration: diff --git a/doc/source/whatsnew/v0.23.0.txt b/doc/source/whatsnew/v0.23.0.txt index a976fca66a57a..5da88e76628e8 100644 --- a/doc/source/whatsnew/v0.23.0.txt +++ b/doc/source/whatsnew/v0.23.0.txt @@ -340,6 +340,7 @@ Other Enhancements - Added option ``display.html.use_mathjax`` so `MathJax `_ can be disabled when rendering tables in ``Jupyter`` notebooks (:issue:`19856`, :issue:`19824`) - :meth:`Timestamp.month_name`, :meth:`DatetimeIndex.month_name`, and :meth:`Series.dt.month_name` are now available (:issue:`12805`) - :meth:`Timestamp.day_name` and :meth:`DatetimeIndex.day_name` are now available to return day names with a specified locale (:issue:`12806`) +- :func:`DataFrame.rename_axis` supports ``index`` and ``columns`` arguments and :func:`Series.rename_axis` supports ``index`` argument (:issue:`19978`) .. _whatsnew_0230.api_breaking: diff --git a/pandas/core/generic.py b/pandas/core/generic.py index ae16bae6d7abe..ec8cc9e368f23 100644 --- a/pandas/core/generic.py +++ b/pandas/core/generic.py @@ -748,9 +748,9 @@ def swaplevel(self, i=-2, j=-1, axis=0): # ---------------------------------------------------------------------- # Rename - + # renamer function if passed a dict - def _get_rename_function(mapper): + def _get_rename_function(self, mapper): if isinstance(mapper, (dict, ABCSeries)): def f(x): @@ -912,16 +912,20 @@ def rename(self, *args, **kwargs): rename.__doc__ = _shared_docs['rename'] - def rename_axis(self, s=None, **kwargs): + def rename_axis(self, mapper=None, **kwargs): """Alter the name of the index or name of index backing the columns. Parameters ---------- - s, index, columns : dict-like or function, optional + mapper : scalar, list-like, optional + Value to set the axis name attribute. + index, columns : scalar, list-like, dict-like or function, optional dict-like or functions transformations to apply to - that axis' values. Use either ``s`` and ``axis`` to - specify the axis to target with ``s``, or ``index`` + that axis' values. + + Use either ``mapper`` and ``axis`` to + specify the axis to target with ``mapper``, or ``index`` and/or ``columns``. axis : int or string, default 0 copy : boolean, default True @@ -938,21 +942,21 @@ def rename_axis(self, s=None, **kwargs): the axis *labels* by passing a mapping or scalar. This behavior is deprecated and will be removed in a future version. Use ``rename`` instead. - + ``DataFrame.rename_axis`` supports two calling conventions * ``(index=index_mapper, columns=columns_mapper, ...)`` - * ``(s, axis={'index', 'columns'}, ...)`` + * ``(mapper, axis={'index', 'columns'}, ...)`` The first calling convention will only modify the names of the index and/or the names of the index backing the columns. In this case, the parameter ``copy`` is ignored. - + The second calling convention will modify the names of the - the corresponding index if s is a list or a scalar. - However, if s is dict-like or a function, it will use the - deprecated behavior of modifying the axis *labels*. - + the corresponding index if mapper is a list or a scalar. + However, if mapper is dict-like or a function, it will use the + deprecated behavior of modifying the axis *labels*. + We *highly* recommend using keyword arguments to clarify your intent. @@ -978,11 +982,47 @@ def rename_axis(self, s=None, **kwargs): 1 2 5 2 3 6 + >>> mi = pd.MultiIndex.from_product([['a', 'b', 'c'], [1, 2]], + names=['let','num']) + >>> df = pd.DataFrame({'x': [i for i in range(len(mi))], + 'y' : [i*10 for i in range(len(mi))]}, + index=mi) + >>> df.rename_axis(index={'num' : 'n'}) + x y + let n + a 1 0 0 + 2 1 10 + b 1 2 20 + 2 3 30 + c 1 4 40 + 2 5 50 + + >>> cdf = df.rename_axis(columns='col') + >>> cdf + col x y + let num + a 1 0 0 + 2 1 10 + b 1 2 20 + 2 3 30 + c 1 4 40 + 2 5 50 + + >>> cdf.rename_axis(columns=str.upper) + COL x y + let num + a 1 0 0 + 2 1 10 + b 1 2 20 + 2 3 30 + c 1 4 40 + 2 5 50 + """ axes, kwargs = self._construct_axes_from_arguments((), kwargs) copy = kwargs.pop('copy', True) inplace = kwargs.pop('inplace', False) - axis = kwargs.pop('axis', None) + axis = kwargs.pop('axis', 0) if axis is not None: axis = self._get_axis_number(axis) @@ -990,20 +1030,22 @@ def rename_axis(self, s=None, **kwargs): raise TypeError('rename_axis() got an unexpected keyword ' 'argument "{0}"'.format(list(kwargs.keys())[0])) inplace = validate_bool_kwarg(inplace, 'inplace') - - if (s is not None): - # Use old behavior if a scalar or list - non_mapper = is_scalar(s) or (is_list_like(s) and not - is_dict_like(s)) + + if (mapper is not None): + # Use v0.23 behavior if a scalar or list + non_mapper = is_scalar(mapper) or (is_list_like(mapper) and not + is_dict_like(mapper)) if non_mapper: - return self._set_axis_name(s, axis=axis, inplace=inplace) + return self._set_axis_name(mapper, axis=axis, inplace=inplace) else: + # Deprecated (v0.21) behavior is if mapper is specified, + # and not a list or scalar, then call rename msg = ("Using 'rename_axis' to alter labels is deprecated. " "Use '.rename' instead") warnings.warn(msg, FutureWarning, stacklevel=2) axis = self._get_axis_name(axis) d = {'copy': copy, 'inplace': inplace} - d[axis] = s + d[axis] = mapper return self.rename(**d) else: # Use new behavior. Means that index and/or columns @@ -1014,9 +1056,14 @@ def rename_axis(self, s=None, **kwargs): v = axes.get(self._AXIS_NAMES[axis]) if v is None: continue - f = self._get_rename_function(v) - curnames = self._get_axis(axis).names - newnames = [f(name) for name in curnames] + non_mapper = is_scalar(v) or (is_list_like(v) and not + is_dict_like(v)) + if non_mapper: + newnames = v + else: + f = self._get_rename_function(v) + curnames = self._get_axis(axis).names + newnames = [f(name) for name in curnames] result._set_axis_name(newnames, axis=axis, inplace=True) if not inplace: diff --git a/pandas/tests/frame/test_alter_axes.py b/pandas/tests/frame/test_alter_axes.py index 9faad2baaf84d..641b7af4b7942 100644 --- a/pandas/tests/frame/test_alter_axes.py +++ b/pandas/tests/frame/test_alter_axes.py @@ -451,46 +451,63 @@ def test_rename_axis_inplace(self): assert no_return is None assert_frame_equal(result, expected) -# def test_rename_axis_warns(self): -# # https://github.com/pandas-dev/pandas/issues/17833 -# df = pd.DataFrame({"A": [1, 2], "B": [1, 2]}) -# with tm.assert_produces_warning(FutureWarning) as w: -# df.rename_axis(id, axis=0) -# assert 'rename' in str(w[0].message) -# -# with tm.assert_produces_warning(FutureWarning) as w: -# df.rename_axis({0: 10, 1: 20}, axis=0) -# assert 'rename' in str(w[0].message) -# -# with tm.assert_produces_warning(FutureWarning) as w: -# df.rename_axis(id, axis=1) -# assert 'rename' in str(w[0].message) -# -# with tm.assert_produces_warning(FutureWarning) as w: -# df['A'].rename_axis(id) -# assert 'rename' in str(w[0].message) + def test_rename_axis_warns(self): + # https://github.com/pandas-dev/pandas/issues/17833 + df = pd.DataFrame({"A": [1, 2], "B": [1, 2]}) + with tm.assert_produces_warning(FutureWarning) as w: + df.rename_axis(id, axis=0) + assert 'rename' in str(w[0].message) - def test_rename_axis_mapper(self): - mi = pd.MultiIndex.from_product([['a', 'b', 'c'], [1, 2]], - names=['ll', 'nn']) + with tm.assert_produces_warning(FutureWarning) as w: + df.rename_axis({0: 10, 1: 20}, axis=0) + assert 'rename' in str(w[0].message) + + with tm.assert_produces_warning(FutureWarning) as w: + df.rename_axis(id, axis=1) + assert 'rename' in str(w[0].message) - df = pd.DataFrame({'x': [i for i in range(len(mi))], - 'y' : [i*10 for i in range(len(mi))]}, - index=mi) + with tm.assert_produces_warning(FutureWarning) as w: + df['A'].rename_axis(id) + assert 'rename' in str(w[0].message) + + def test_rename_axis_mapper(self): + # GH 19978 + mi = MultiIndex.from_product([['a', 'b', 'c'], [1, 2]], + names=['ll', 'nn']) + df = DataFrame({'x': [i for i in range(len(mi))], + 'y': [i * 10 for i in range(len(mi))]}, + index=mi) result = df.rename_axis('cols', axis=1) - tm.assert_index_equal(result.columns, - pd.Index(['x', 'y'], name='cols')) - - result = result.rename_axis({'cols' : 'new'}, axis=1) - tm.assert_index_equal(result.columns, - pd.Index(['x', 'y'], name='new')) - - result = df.rename_axis({'ll' : 'foo'}) + tm.assert_index_equal(result.columns, + Index(['x', 'y'], name='cols')) + + result = result.rename_axis(columns={'cols': 'new'}, axis=1) + tm.assert_index_equal(result.columns, + Index(['x', 'y'], name='new')) + + result = df.rename_axis(index={'ll': 'foo'}) assert result.index.names == ['foo', 'nn'] - - result = df.rename_axis(str.upper, axis=0) + + result = df.rename_axis(index=str.upper, axis=0) assert result.index.names == ['LL', 'NN'] - + + result = df.rename_axis(index=['foo', 'goo']) + assert result.index.names == ['foo', 'goo'] + + sdf = df.reset_index().set_index('nn').drop(columns=['ll', 'y']) + result = sdf.rename_axis(index='foo', columns='meh') + assert result.index.name == 'foo' + assert result.columns.name == 'meh' + + with tm.assert_raises_regex(TypeError, 'Must pass'): + df.rename_axis(index='wrong') + + with tm.assert_raises_regex(ValueError, 'Length of names'): + df.rename_axis(index=['wrong']) + + with tm.assert_raises_regex(TypeError, 'bogus'): + df.rename_axis(bogus=None) + def test_rename_multiindex(self): tuples_index = [('foo1', 'bar1'), ('foo2', 'bar2')] diff --git a/pandas/tests/io/test_pytables.py b/pandas/tests/io/test_pytables.py index b3e2a5bf008ce..e8f7717a87774 100644 --- a/pandas/tests/io/test_pytables.py +++ b/pandas/tests/io/test_pytables.py @@ -1289,7 +1289,7 @@ def test_append_with_strings(self): with catch_warnings(record=True): wp = tm.makePanel() wp2 = wp.rename( - minor_axis = {x: "%s_extra" % x for x in wp.minor_axis}) + minor_axis={x: "%s_extra" % x for x in wp.minor_axis}) def check_col(key, name, size): assert getattr(store.get_storer(key) diff --git a/pandas/tests/reshape/test_concat.py b/pandas/tests/reshape/test_concat.py index b20a2ce99b3c2..20181d83b3d50 100644 --- a/pandas/tests/reshape/test_concat.py +++ b/pandas/tests/reshape/test_concat.py @@ -1402,7 +1402,7 @@ def df(): panel2 = make_panel() panel2 = panel2.rename(major_axis=dict((x, "%s_1" % x) - for x in panel2.major_axis)) + for x in panel2.major_axis)) panel3 = panel2.rename(major_axis=lambda x: '%s_1' % x) panel3 = panel3.rename(minor_axis=lambda x: '%s_1' % x) diff --git a/pandas/tests/series/test_alter_axes.py b/pandas/tests/series/test_alter_axes.py index dce4e82cbdcf1..1fa8039f59c27 100644 --- a/pandas/tests/series/test_alter_axes.py +++ b/pandas/tests/series/test_alter_axes.py @@ -222,6 +222,24 @@ def test_reorder_levels(self): expected = Series(np.arange(6), index=e_idx) assert_series_equal(result, expected) + def test_rename_axis_mapper(self): + # GH 19978 + mi = MultiIndex.from_product([['a', 'b', 'c'], [1, 2]], + names=['ll', 'nn']) + s = Series([i for i in range(len(mi))], index=mi) + + result = s.rename_axis(index={'ll': 'foo'}) + assert result.index.names == ['foo', 'nn'] + + result = s.rename_axis(index=str.upper, axis=0) + assert result.index.names == ['LL', 'NN'] + + result = s.rename_axis(index=['foo', 'goo']) + assert result.index.names == ['foo', 'goo'] + + with tm.assert_raises_regex(TypeError, 'unexpected'): + s.rename_axis(columns='wrong') + def test_rename_axis_inplace(self): # GH 15704 series = self.ts.copy() From a14e6a1e66a3bc74aad7f9654ec51e4508eb0fed Mon Sep 17 00:00:00 2001 From: Dr-Irv Date: Thu, 8 Mar 2018 14:41:38 -0500 Subject: [PATCH 05/12] Doc changes and resolve conflicts with master --- pandas/core/generic.py | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/pandas/core/generic.py b/pandas/core/generic.py index 0ac49033aa23a..e5467f780f8e6 100644 --- a/pandas/core/generic.py +++ b/pandas/core/generic.py @@ -751,6 +751,10 @@ def swaplevel(self, i=-2, j=-1, axis=0): # renamer function if passed a dict def _get_rename_function(self, mapper): + """ + Returns a function that will map names/labels, dependent if mapper + is a dict, Series or just a function. + """ if isinstance(mapper, (dict, ABCSeries)): def f(x): @@ -913,8 +917,7 @@ def rename(self, *args, **kwargs): rename.__doc__ = _shared_docs['rename'] def rename_axis(self, mapper=None, **kwargs): - """Alter the name of the index or name of index backing the - columns. + """Alter the name of the index or name of index backing the columns. Parameters ---------- From 5806d9aa6a05de21d0fdc95878a5c9a973339097 Mon Sep 17 00:00:00 2001 From: Dr-Irv Date: Mon, 9 Jul 2018 16:13:44 -0400 Subject: [PATCH 06/12] Fix doc merge --- doc/source/basics.rst | 2 +- doc/source/whatsnew/v0.23.0.txt | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/doc/source/basics.rst b/doc/source/basics.rst index a63887b3f5034..8d465521af816 100644 --- a/doc/source/basics.rst +++ b/doc/source/basics.rst @@ -1469,7 +1469,7 @@ any of its three axes. .. _basics.rename_axis: -.. versionadded:: 0.23.0 +.. versionadded:: 0.24.0 The methods :meth:`~DataFrame.rename_axis` and :meth:`~Series.rename_axis` allow specific names of a `MultiIndex` to be changed (as opposed to the diff --git a/doc/source/whatsnew/v0.23.0.txt b/doc/source/whatsnew/v0.23.0.txt index 3a9dcdbcc2131..7509c502f27ed 100644 --- a/doc/source/whatsnew/v0.23.0.txt +++ b/doc/source/whatsnew/v0.23.0.txt @@ -550,7 +550,6 @@ Other Enhancements - :func:`to_hdf` and :func:`read_hdf` now accept an ``errors`` keyword argument to control encoding error handling (:issue:`20835`) - :func:`cut` has gained the ``duplicates='raise'|'drop'`` option to control whether to raise on duplicated edges (:issue:`20947`) - :func:`date_range`, :func:`timedelta_range`, and :func:`interval_range` now return a linearly spaced index if ``start``, ``stop``, and ``periods`` are specified, but ``freq`` is not. (:issue:`20808`, :issue:`20983`, :issue:`20976`) ->>>>>>> upstream/master .. _whatsnew_0230.api_breaking: From 2f5368515d3558b16b631441de4bee29b1021b38 Mon Sep 17 00:00:00 2001 From: Dr-Irv Date: Tue, 25 Sep 2018 14:59:08 -0400 Subject: [PATCH 07/12] fix flake8 issue --- pandas/tests/reshape/test_concat.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pandas/tests/reshape/test_concat.py b/pandas/tests/reshape/test_concat.py index 1244fd34020b2..d9bd6330d48ee 100644 --- a/pandas/tests/reshape/test_concat.py +++ b/pandas/tests/reshape/test_concat.py @@ -1552,8 +1552,8 @@ def df(): panel1 = make_panel() panel2 = make_panel() - panel2 = panel2.rename(major_axis=dict((x, "%s_1" % x) - for x in panel2.major_axis)) + panel2 = panel2.rename(major_axis={x: "%s_1" % x + for x in panel2.major_axis}) panel3 = panel2.rename(major_axis=lambda x: '%s_1' % x) panel3 = panel3.rename(minor_axis=lambda x: '%s_1' % x) From 5fd1ddf87189e9344e178cbea20a29c0165b223a Mon Sep 17 00:00:00 2001 From: Dr-Irv Date: Wed, 26 Sep 2018 10:58:36 -0400 Subject: [PATCH 08/12] Make whatsnew show example --- doc/source/whatsnew/v0.24.0.txt | 23 +++++++++++++++++++++-- 1 file changed, 21 insertions(+), 2 deletions(-) diff --git a/doc/source/whatsnew/v0.24.0.txt b/doc/source/whatsnew/v0.24.0.txt index b9b0f8a8f1dc7..cbf5b48b88c54 100644 --- a/doc/source/whatsnew/v0.24.0.txt +++ b/doc/source/whatsnew/v0.24.0.txt @@ -162,6 +162,26 @@ array, but rather an ``ExtensionArray``: This is the same behavior as ``Series.values`` for categorical data. See :ref:`whatsnew_0240.api_breaking.interval_values` for more. +.. _whatsnew_0240.enhancements.rename_axis: + +Renaming names in a MultiIndex +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +:func:`DataFrame.rename_axis` now supports ``index`` and ``columns`` arguments +and :func:`Series.rename_axis` supports ``index`` argument (:issue:`19978`) + +This change allows a dictionary to be passed so that some of the names +of a ``MultiIndex`` can be changed. + +Example: + +.. ipython:: python + + mi = pd.MultiIndex.from_product([list('AB'), list('CD'), list('EF')], + names=['AB', 'CD', 'EF']) + df = pd.DataFrame([i for i in range(len(mi))], index=mi, columns=['N']) + df + df.rename_axis(index={'CD': 'New'}) .. _whatsnew_0240.enhancements.other: @@ -181,8 +201,7 @@ Other Enhancements - :func:`read_html` copies cell data across ``colspan`` and ``rowspan``, and it treats all-``th`` table rows as headers if ``header`` kwarg is not given and there is no ``thead`` (:issue:`17054`) - :meth:`Series.nlargest`, :meth:`Series.nsmallest`, :meth:`DataFrame.nlargest`, and :meth:`DataFrame.nsmallest` now accept the value ``"all"`` for the ``keep`` argument. This keeps all ties for the nth largest/smallest value (:issue:`16818`) - :class:`IntervalIndex` has gained the :meth:`~IntervalIndex.set_closed` method to change the existing ``closed`` value (:issue:`21670`) -- :func:`~DataFrame.to_csv` and :func:`~DataFrame.to_json` now support ``compression='infer'`` to infer compression based on filename (:issue:`15008`) -- :func:`DataFrame.rename_axis` supports ``index`` and ``columns`` arguments and :func:`Series.rename_axis` supports ``index`` argument (:issue:`19978`) +- :func:`~DataFrame.to_csv`, :func:`~Series.to_csv`, :func:`~DataFrame.to_json`, and :func:`~Series.to_json` now support ``compression='infer'`` to infer compression based on filename extension (:issue:`15008`). The default compression for ``to_csv``, ``to_json``, and ``to_pickle`` methods has been updated to ``'infer'`` (:issue:`22004`). - :func:`to_timedelta` now supports iso-formated timedelta strings (:issue:`21877`) - :class:`Series` and :class:`DataFrame` now support :class:`Iterable` in constructor (:issue:`2193`) From 3e8aaf31bc55dd37a82baf62e0e9b78a20224b3f Mon Sep 17 00:00:00 2001 From: Dr-Irv Date: Wed, 26 Sep 2018 15:42:36 -0400 Subject: [PATCH 09/12] fix docstring --- pandas/core/generic.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/pandas/core/generic.py b/pandas/core/generic.py index 5265b4788e1aa..7400a3fe85cb4 100644 --- a/pandas/core/generic.py +++ b/pandas/core/generic.py @@ -1219,10 +1219,10 @@ def rename_axis(self, mapper=None, **kwargs): 2 3 6 >>> mi = pd.MultiIndex.from_product([['a', 'b', 'c'], [1, 2]], - names=['let','num']) + ... names=['let','num']) >>> df = pd.DataFrame({'x': [i for i in range(len(mi))], - 'y' : [i*10 for i in range(len(mi))]}, - index=mi) + ... 'y' : [i*10 for i in range(len(mi))]}, + ... index=mi) >>> df.rename_axis(index={'num' : 'n'}) x y let n From 0542cf0a69fdd1c2a5ece7f265fb50c8bba3d01b Mon Sep 17 00:00:00 2001 From: Dr-Irv Date: Wed, 24 Oct 2018 11:13:20 -0400 Subject: [PATCH 10/12] doc fix. Move get_rename_function to common --- doc/source/basics.rst | 3 --- pandas/core/common.py | 18 ++++++++++++++++++ pandas/core/generic.py | 25 +++++-------------------- 3 files changed, 23 insertions(+), 23 deletions(-) diff --git a/doc/source/basics.rst b/doc/source/basics.rst index 2129dd49dc05d..b6264c4071fc4 100644 --- a/doc/source/basics.rst +++ b/doc/source/basics.rst @@ -1464,9 +1464,6 @@ for altering the ``Series.name`` attribute. s.rename("scalar-name") -The Panel class has a related :meth:`~Panel.rename` class which can rename -any of its three axes. - .. _basics.rename_axis: .. versionadded:: 0.24.0 diff --git a/pandas/core/common.py b/pandas/core/common.py index f6e40faa79740..161f2a556e661 100644 --- a/pandas/core/common.py +++ b/pandas/core/common.py @@ -454,3 +454,21 @@ def _pipe(obj, func, *args, **kwargs): return func(*args, **kwargs) else: return func(obj, *args, **kwargs) + + +def get_rename_function(mapper): + """ + Returns a function that will map names/labels, dependent if mapper + is a dict, Series or just a function. + """ + if isinstance(mapper, (dict, ABCSeries)): + + def f(x): + if x in mapper: + return mapper[x] + else: + return x + else: + f = mapper + + return f diff --git a/pandas/core/generic.py b/pandas/core/generic.py index 4b78a1b558f68..4c0939ddae5da 100644 --- a/pandas/core/generic.py +++ b/pandas/core/generic.py @@ -963,24 +963,6 @@ def swaplevel(self, i=-2, j=-1, axis=0): # ---------------------------------------------------------------------- # Rename - # renamer function if passed a dict - def _get_rename_function(self, mapper): - """ - Returns a function that will map names/labels, dependent if mapper - is a dict, Series or just a function. - """ - if isinstance(mapper, (dict, ABCSeries)): - - def f(x): - if x in mapper: - return mapper[x] - else: - return x - else: - f = mapper - - return f - def rename(self, *args, **kwargs): """ Alter axes input function or functions. Function / dict values must be @@ -1106,7 +1088,7 @@ def rename(self, *args, **kwargs): v = axes.get(self._AXIS_NAMES[axis]) if v is None: continue - f = self._get_rename_function(v) + f = com.get_rename_function(v) baxis = self._get_block_manager_axis(axis) if level is not None: @@ -1135,6 +1117,9 @@ def rename_axis(self, mapper=None, **kwargs): Use either ``mapper`` and ``axis`` to specify the axis to target with ``mapper``, or ``index`` and/or ``columns``. + + .. versionchanged:: 0.24.0 + axis : int or string, default 0 copy : boolean, default True Also copy underlying data. @@ -1285,7 +1270,7 @@ def rename_axis(self, mapper=None, **kwargs): if non_mapper: newnames = v else: - f = self._get_rename_function(v) + f = com.get_rename_function(v) curnames = self._get_axis(axis).names newnames = [f(name) for name in curnames] result._set_axis_name(newnames, axis=axis, From 39938a12b8d386f30a25f3dc218397465291a710 Mon Sep 17 00:00:00 2001 From: Dr-Irv Date: Thu, 25 Oct 2018 15:01:16 -0400 Subject: [PATCH 11/12] Fix signature of rename_axis, add docs --- doc/source/advanced.rst | 41 +++++++++++++++++++++++++++ pandas/core/common.py | 2 +- pandas/core/generic.py | 8 ++++-- pandas/tests/frame/test_alter_axes.py | 12 +++++--- 4 files changed, 56 insertions(+), 7 deletions(-) diff --git a/doc/source/advanced.rst b/doc/source/advanced.rst index 835c4cc9d4ab3..608e2c8e72ded 100644 --- a/doc/source/advanced.rst +++ b/doc/source/advanced.rst @@ -503,6 +503,47 @@ method, allowing you to permute the hierarchical index levels in one step: df[:5].reorder_levels([1,0], axis=0) +.. _advanced.index_names: + +Renaming names of an ``Index`` or ``MultiIndex`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +The :meth:`~DataFrame.rename` method is used to rename the labels of a +``MultiIndex``, and is typically used to rename the columns of a ``DataFrame``. +The ``columns`` argument of ``rename`` allows a dictionary to be specified +that includes only the columns you wish to rename. + +.. ipython:: python + + df.rename(columns={0: "col0", 1: "col1"}) + +This method can also be used to rename specific labels of the main index +of the ``DataFrame``. + +.. ipython:: python + + df.rename(index={"one" : "two", "y" : "z"}) + +The :meth:`~DataFrame.rename_axis` method is used to rename the name of a +``Index`` or ``MultiIndex``. In particular, the names of the levels of a +``MultiIndex`` can be specified, which is useful if ``reset_index()`` is later +used to move the values from the ``MultiIndex`` to a column. + +.. ipython:: python + + df.rename_axis(index=['abc', 'def']) + +Note that the columns of a ``DataFrame`` are an index, so that using +``rename_axis`` with the ``columns`` argument will change the name of that +index. + +.. ipython:: python + + df.rename_axis(columns="Cols").columns + +Both ``rename`` and ``rename_axis`` support specifying a dictionary, +``Series`` or a mapping function to map labels/names to new values. + Sorting a ``MultiIndex`` ------------------------ diff --git a/pandas/core/common.py b/pandas/core/common.py index 161f2a556e661..4bb860c2dbe7c 100644 --- a/pandas/core/common.py +++ b/pandas/core/common.py @@ -461,7 +461,7 @@ def get_rename_function(mapper): Returns a function that will map names/labels, dependent if mapper is a dict, Series or just a function. """ - if isinstance(mapper, (dict, ABCSeries)): + if isinstance(mapper, (compat.Mapping, ABCSeries)): def f(x): if x in mapper: diff --git a/pandas/core/generic.py b/pandas/core/generic.py index 4c0939ddae5da..349a8e35d9b69 100644 --- a/pandas/core/generic.py +++ b/pandas/core/generic.py @@ -54,6 +54,7 @@ from pandas.core.ops import _align_method_FRAME import pandas.core.nanops as nanops from pandas.util._decorators import (Appender, Substitution, + rewrite_axis_style_signature, deprecate_kwarg) from pandas.util._validators import validate_bool_kwarg, validate_fillna_kwargs from pandas.core import config @@ -1102,9 +1103,12 @@ def rename(self, *args, **kwargs): else: return result.__finalize__(self) + @rewrite_axis_style_signature('mapper', [('copy', True), + ('inplace', False)]) def rename_axis(self, mapper=None, **kwargs): """ - Alter the name of the index or name of index backing the columns. + Alter the name of the index or name of Index object that is the + columns. Parameters ---------- @@ -1145,7 +1149,7 @@ def rename_axis(self, mapper=None, **kwargs): * ``(mapper, axis={'index', 'columns'}, ...)`` The first calling convention will only modify the names of - the index and/or the names of the index backing the columns. + the index and/or the names of the Index object that is the columns. In this case, the parameter ``copy`` is ignored. The second calling convention will modify the names of the diff --git a/pandas/tests/frame/test_alter_axes.py b/pandas/tests/frame/test_alter_axes.py index 98a461e530e3e..43deacb8fa247 100644 --- a/pandas/tests/frame/test_alter_axes.py +++ b/pandas/tests/frame/test_alter_axes.py @@ -522,19 +522,23 @@ def test_rename_axis_inplace(self, float_frame): def test_rename_axis_warns(self): # https://github.com/pandas-dev/pandas/issues/17833 df = DataFrame({"A": [1, 2], "B": [1, 2]}) - with tm.assert_produces_warning(FutureWarning) as w: + with tm.assert_produces_warning(FutureWarning, + check_stacklevel=False) as w: df.rename_axis(id, axis=0) assert 'rename' in str(w[0].message) - with tm.assert_produces_warning(FutureWarning) as w: + with tm.assert_produces_warning(FutureWarning, + check_stacklevel=False) as w: df.rename_axis({0: 10, 1: 20}, axis=0) assert 'rename' in str(w[0].message) - with tm.assert_produces_warning(FutureWarning) as w: + with tm.assert_produces_warning(FutureWarning, + check_stacklevel=False) as w: df.rename_axis(id, axis=1) assert 'rename' in str(w[0].message) - with tm.assert_produces_warning(FutureWarning) as w: + with tm.assert_produces_warning(FutureWarning, + check_stacklevel=False) as w: df['A'].rename_axis(id) assert 'rename' in str(w[0].message) From e965c5b603595a8454933e479e7ce74445b2c6e2 Mon Sep 17 00:00:00 2001 From: Dr-Irv Date: Fri, 26 Oct 2018 17:53:42 -0400 Subject: [PATCH 12/12] stacklevel for warnings --- pandas/core/generic.py | 2 +- pandas/tests/frame/test_alter_axes.py | 12 ++++-------- 2 files changed, 5 insertions(+), 9 deletions(-) diff --git a/pandas/core/generic.py b/pandas/core/generic.py index 502885f6a36b5..c3d40459bb097 100644 --- a/pandas/core/generic.py +++ b/pandas/core/generic.py @@ -1255,7 +1255,7 @@ def rename_axis(self, mapper=None, **kwargs): # and not a list or scalar, then call rename msg = ("Using 'rename_axis' to alter labels is deprecated. " "Use '.rename' instead") - warnings.warn(msg, FutureWarning, stacklevel=2) + warnings.warn(msg, FutureWarning, stacklevel=3) axis = self._get_axis_name(axis) d = {'copy': copy, 'inplace': inplace} d[axis] = mapper diff --git a/pandas/tests/frame/test_alter_axes.py b/pandas/tests/frame/test_alter_axes.py index e9e8c10d0ce0a..0752c125b75eb 100644 --- a/pandas/tests/frame/test_alter_axes.py +++ b/pandas/tests/frame/test_alter_axes.py @@ -522,23 +522,19 @@ def test_rename_axis_inplace(self, float_frame): def test_rename_axis_warns(self): # https://github.com/pandas-dev/pandas/issues/17833 df = DataFrame({"A": [1, 2], "B": [1, 2]}) - with tm.assert_produces_warning(FutureWarning, - check_stacklevel=False) as w: + with tm.assert_produces_warning(FutureWarning) as w: df.rename_axis(id, axis=0) assert 'rename' in str(w[0].message) - with tm.assert_produces_warning(FutureWarning, - check_stacklevel=False) as w: + with tm.assert_produces_warning(FutureWarning) as w: df.rename_axis({0: 10, 1: 20}, axis=0) assert 'rename' in str(w[0].message) - with tm.assert_produces_warning(FutureWarning, - check_stacklevel=False) as w: + with tm.assert_produces_warning(FutureWarning) as w: df.rename_axis(id, axis=1) assert 'rename' in str(w[0].message) - with tm.assert_produces_warning(FutureWarning, - check_stacklevel=False) as w: + with tm.assert_produces_warning(FutureWarning) as w: df['A'].rename_axis(id) assert 'rename' in str(w[0].message)