From d95308f714c52fb6b814d00fd45cf6b31c13e90d Mon Sep 17 00:00:00 2001 From: phofl Date: Sat, 28 Nov 2020 02:17:29 +0100 Subject: [PATCH 01/14] ENH: Implement dict-like support for rename and set_names in MultiIndex --- doc/source/whatsnew/v1.2.0.rst | 1 + pandas/core/indexes/base.py | 25 +++++++++++++++--- pandas/tests/indexes/multi/test_names.py | 33 ++++++++++++++++++++++++ 3 files changed, 56 insertions(+), 3 deletions(-) diff --git a/doc/source/whatsnew/v1.2.0.rst b/doc/source/whatsnew/v1.2.0.rst index 08edc7531bcd6..6b360e440c1e3 100644 --- a/doc/source/whatsnew/v1.2.0.rst +++ b/doc/source/whatsnew/v1.2.0.rst @@ -257,6 +257,7 @@ Other enhancements - Improve numerical stability for :meth:`.Rolling.skew`, :meth:`.Rolling.kurt`, :meth:`Expanding.skew` and :meth:`Expanding.kurt` through implementation of Kahan summation (:issue:`6929`) - Improved error reporting for subsetting columns of a :class:`.DataFrameGroupBy` with ``axis=1`` (:issue:`37725`) - Implement method ``cross`` for :meth:`DataFrame.merge` and :meth:`DataFrame.join` (:issue:`5401`) +- Add support for dict-like names in :class:`MultiIndex.set_names` and :class:`MultiIndex.rename` (:issue:`20421`) .. --------------------------------------------------------------------------- diff --git a/pandas/core/indexes/base.py b/pandas/core/indexes/base.py index c074ae2c066f6..0ce1fe3fdd377 100644 --- a/pandas/core/indexes/base.py +++ b/pandas/core/indexes/base.py @@ -29,6 +29,7 @@ from pandas._libs.tslibs.timezones import tz_compare from pandas._typing import AnyArrayLike, Dtype, DtypeObj, Label, Shape, final from pandas.compat.numpy import function as nv +from pandas.core.dtypes.inference import is_dict_like from pandas.errors import DuplicateLabelError, InvalidIndexError from pandas.util._decorators import Appender, cache_readonly, doc @@ -1319,11 +1320,11 @@ def set_names(self, names, level=None, inplace: bool = False): Parameters ---------- - names : label or list of label + names : label or list of label or dict-like for MultiIndex 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. + If the index is a MultiIndex and names is not dict-like, 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. @@ -1366,6 +1367,12 @@ def set_names(self, names, level=None, inplace: bool = False): ( 'cobra', 2018), ( 'cobra', 2019)], names=['species', 'year']) + >>> idx.set_names({'species': 'snake'}) + MultiIndex([('python', 2018), + ('python', 2019), + ( 'cobra', 2018), + ( 'cobra', 2019)], + names=['snake', 'year']) """ if level is not None and not isinstance(self, ABCMultiIndex): raise ValueError("Level must be None for non-MultiIndex") @@ -1376,6 +1383,12 @@ def set_names(self, names, level=None, inplace: bool = False): if not is_list_like(names) and level is None and self.nlevels > 1: raise TypeError("Must pass list-like as `names`.") + if is_dict_like(names) and not isinstance(self, ABCMultiIndex): + raise TypeError("Can only pass dict-like as `names` for MultiIndex.") + + if is_dict_like(names) and level is not None: + raise TypeError("Can not pass level when passing dict-like as `names`.") + if not is_list_like(names): names = [names] if level is not None and not is_list_like(level): @@ -1385,6 +1398,12 @@ def set_names(self, names, level=None, inplace: bool = False): idx = self else: idx = self._shallow_copy() + + if isinstance(self, ABCMultiIndex) and is_dict_like(names): + level = Index(self.names).get_indexer_for(names) + level = level[level>-1] + names = [names[key] for key in np.array(self.names)[level]] + idx._set_names(names, level=level) if not inplace: return idx diff --git a/pandas/tests/indexes/multi/test_names.py b/pandas/tests/indexes/multi/test_names.py index 891380b35a8be..ef1b400144661 100644 --- a/pandas/tests/indexes/multi/test_names.py +++ b/pandas/tests/indexes/multi/test_names.py @@ -148,3 +148,36 @@ def test_setting_names_from_levels_raises(): assert pd.Index._no_setting_name is False assert pd.Int64Index._no_setting_name is False assert pd.RangeIndex._no_setting_name is False + + +@pytest.mark.parametrize("func", ["rename", "set_names"]) +@pytest.mark.parametrize( + "rename_dict, exp_names", + [ + ({"x": "z"}, ["z", "y", "z"]), + ({"x": "z", "y": "x"}, ["z", "x", "z"]), + ({"y": "z"}, ["x", "z", "x"]), + ({}, ["x", "y", "x"]), + ({"z": "a"}, ["x", "y", "x"]), + ({"y": "z", "a": "b"}, ["x", "z", "x"]) + ]) +def test_name_mi_with_dict_like(func, rename_dict, exp_names): + # GH#20421 + mi = MultiIndex.from_arrays([[1, 2], [3, 4], [5, 6]], names=['x', 'y', 'x']) + result = getattr(mi, func)(rename_dict) + expected = MultiIndex.from_arrays([[1, 2], [3, 4], [5, 6]], names=exp_names) + tm.assert_index_equal(result, expected) + + +def test_name_with_dict_like_raising(): + # GH#20421 + mi = MultiIndex.from_arrays([[1, 2], [3, 4]], names=['x', 'y']) + + msg = "Can not pass level when passing dict-like as `names`." + with pytest.raises(TypeError, match=msg): + mi.set_names({"x": "z"}, level=[0, 1]) + + ix = pd.Index([1, 2]) + msg = "Can only pass dict-like as `names` for MultiIndex." + with pytest.raises(TypeError, match=msg): + ix.set_names({"x": "z"}) From d1ec051d130bbfe9a13de0a12b59aadb59d9bffc Mon Sep 17 00:00:00 2001 From: phofl Date: Sat, 28 Nov 2020 02:19:14 +0100 Subject: [PATCH 02/14] Run black --- pandas/core/indexes/base.py | 2 +- pandas/tests/indexes/multi/test_names.py | 9 +++++---- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/pandas/core/indexes/base.py b/pandas/core/indexes/base.py index 0ce1fe3fdd377..46fa48b1f45fe 100644 --- a/pandas/core/indexes/base.py +++ b/pandas/core/indexes/base.py @@ -1401,7 +1401,7 @@ def set_names(self, names, level=None, inplace: bool = False): if isinstance(self, ABCMultiIndex) and is_dict_like(names): level = Index(self.names).get_indexer_for(names) - level = level[level>-1] + level = level[level > -1] names = [names[key] for key in np.array(self.names)[level]] idx._set_names(names, level=level) diff --git a/pandas/tests/indexes/multi/test_names.py b/pandas/tests/indexes/multi/test_names.py index ef1b400144661..57a89b1ae6d5e 100644 --- a/pandas/tests/indexes/multi/test_names.py +++ b/pandas/tests/indexes/multi/test_names.py @@ -159,11 +159,12 @@ def test_setting_names_from_levels_raises(): ({"y": "z"}, ["x", "z", "x"]), ({}, ["x", "y", "x"]), ({"z": "a"}, ["x", "y", "x"]), - ({"y": "z", "a": "b"}, ["x", "z", "x"]) - ]) + ({"y": "z", "a": "b"}, ["x", "z", "x"]), + ], +) def test_name_mi_with_dict_like(func, rename_dict, exp_names): # GH#20421 - mi = MultiIndex.from_arrays([[1, 2], [3, 4], [5, 6]], names=['x', 'y', 'x']) + mi = MultiIndex.from_arrays([[1, 2], [3, 4], [5, 6]], names=["x", "y", "x"]) result = getattr(mi, func)(rename_dict) expected = MultiIndex.from_arrays([[1, 2], [3, 4], [5, 6]], names=exp_names) tm.assert_index_equal(result, expected) @@ -171,7 +172,7 @@ def test_name_mi_with_dict_like(func, rename_dict, exp_names): def test_name_with_dict_like_raising(): # GH#20421 - mi = MultiIndex.from_arrays([[1, 2], [3, 4]], names=['x', 'y']) + mi = MultiIndex.from_arrays([[1, 2], [3, 4]], names=["x", "y"]) msg = "Can not pass level when passing dict-like as `names`." with pytest.raises(TypeError, match=msg): From da475c758076b4a2ff360b5b7138c61890ec4658 Mon Sep 17 00:00:00 2001 From: phofl Date: Sat, 28 Nov 2020 02:21:01 +0100 Subject: [PATCH 03/14] Move import --- pandas/core/indexes/base.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pandas/core/indexes/base.py b/pandas/core/indexes/base.py index 46fa48b1f45fe..19c7f94af6c92 100644 --- a/pandas/core/indexes/base.py +++ b/pandas/core/indexes/base.py @@ -29,7 +29,6 @@ from pandas._libs.tslibs.timezones import tz_compare from pandas._typing import AnyArrayLike, Dtype, DtypeObj, Label, Shape, final from pandas.compat.numpy import function as nv -from pandas.core.dtypes.inference import is_dict_like from pandas.errors import DuplicateLabelError, InvalidIndexError from pandas.util._decorators import Appender, cache_readonly, doc @@ -74,6 +73,7 @@ ABCSeries, ABCTimedeltaIndex, ) +from pandas.core.dtypes.inference import is_dict_like from pandas.core.dtypes.missing import array_equivalent, isna from pandas.core import missing, ops From 00c0134115dbb8e523da125b8a8d5554871c3e64 Mon Sep 17 00:00:00 2001 From: phofl Date: Sat, 28 Nov 2020 11:28:50 +0100 Subject: [PATCH 04/14] Fix doc example --- pandas/core/indexes/base.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pandas/core/indexes/base.py b/pandas/core/indexes/base.py index 19c7f94af6c92..3f0dd5026ac5b 100644 --- a/pandas/core/indexes/base.py +++ b/pandas/core/indexes/base.py @@ -1367,7 +1367,7 @@ def set_names(self, names, level=None, inplace: bool = False): ( 'cobra', 2018), ( 'cobra', 2019)], names=['species', 'year']) - >>> idx.set_names({'species': 'snake'}) + >>> idx.set_names({'kind': 'snake'}) MultiIndex([('python', 2018), ('python', 2019), ( 'cobra', 2018), From de76243310ebc68bcce4594e09232dd9a8bffbef Mon Sep 17 00:00:00 2001 From: phofl Date: Sun, 29 Nov 2020 00:23:07 +0100 Subject: [PATCH 05/14] Add comments --- pandas/core/indexes/base.py | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/pandas/core/indexes/base.py b/pandas/core/indexes/base.py index 3f0dd5026ac5b..543ac80f8e30f 100644 --- a/pandas/core/indexes/base.py +++ b/pandas/core/indexes/base.py @@ -1320,11 +1320,18 @@ def set_names(self, names, level=None, inplace: bool = False): Parameters ---------- + names : label or list of label or dict-like for MultiIndex Name(s) to set. + + .. versionchanged:: 1.2.0 + level : int, label or list of int or label, optional If the index is a MultiIndex and names is not dict-like, level(s) to set (None for all levels). Otherwise level must be None. + + .. versionchanged:: 1.2.0 + inplace : bool, default False Modifies the object directly, instead of creating a new Index or MultiIndex. @@ -1367,6 +1374,9 @@ def set_names(self, names, level=None, inplace: bool = False): ( 'cobra', 2018), ( 'cobra', 2019)], names=['species', 'year']) + + When renaming levels through a dictionary no level can't be passed. + >>> idx.set_names({'kind': 'snake'}) MultiIndex([('python', 2018), ('python', 2019), From dbfce8d064e1450ce3fafcc4f12a10493b1da2bc Mon Sep 17 00:00:00 2001 From: phofl Date: Sun, 29 Nov 2020 00:27:21 +0100 Subject: [PATCH 06/14] Use for loop --- pandas/core/indexes/base.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/pandas/core/indexes/base.py b/pandas/core/indexes/base.py index 543ac80f8e30f..106db36f4336e 100644 --- a/pandas/core/indexes/base.py +++ b/pandas/core/indexes/base.py @@ -1410,8 +1410,7 @@ def set_names(self, names, level=None, inplace: bool = False): idx = self._shallow_copy() if isinstance(self, ABCMultiIndex) and is_dict_like(names): - level = Index(self.names).get_indexer_for(names) - level = level[level > -1] + level = [i for i, name in enumerate(self.names) if name in names.keys()] names = [names[key] for key in np.array(self.names)[level]] idx._set_names(names, level=level) From 0f4d773769c731af42443d6a4b81a8d2afdd7a98 Mon Sep 17 00:00:00 2001 From: phofl Date: Sun, 29 Nov 2020 00:46:51 +0100 Subject: [PATCH 07/14] Use regular loop --- pandas/core/indexes/base.py | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/pandas/core/indexes/base.py b/pandas/core/indexes/base.py index 106db36f4336e..63f4540356b71 100644 --- a/pandas/core/indexes/base.py +++ b/pandas/core/indexes/base.py @@ -1410,8 +1410,13 @@ def set_names(self, names, level=None, inplace: bool = False): idx = self._shallow_copy() if isinstance(self, ABCMultiIndex) and is_dict_like(names): - level = [i for i, name in enumerate(self.names) if name in names.keys()] - names = [names[key] for key in np.array(self.names)[level]] + # Transform dict to list of new names and corresponding levels + level, names_adjusted = [], [] + for i, name in enumerate(self.names): + if name in names.keys(): + level.append(i) + names_adjusted.append(names[name]) + names = names_adjusted idx._set_names(names, level=level) if not inplace: From a56a04b736dfaf4b0a8beb152bfd9973f2ca0463 Mon Sep 17 00:00:00 2001 From: phofl Date: Sun, 29 Nov 2020 20:18:42 +0100 Subject: [PATCH 08/14] Remove wrong condition --- pandas/core/indexes/base.py | 25 +++++++++++------------- pandas/tests/indexes/multi/test_names.py | 6 ------ 2 files changed, 11 insertions(+), 20 deletions(-) diff --git a/pandas/core/indexes/base.py b/pandas/core/indexes/base.py index 63f4540356b71..1e6ab7b196930 100644 --- a/pandas/core/indexes/base.py +++ b/pandas/core/indexes/base.py @@ -1387,17 +1387,23 @@ def set_names(self, names, level=None, inplace: bool = False): if level is not None and not isinstance(self, ABCMultiIndex): raise ValueError("Level must be None for non-MultiIndex") - if level is not None and not is_list_like(level) and is_list_like(names): + elif level is not None and not is_list_like(level) and is_list_like(names): raise TypeError("Names must be a string when a single level is provided.") - if not is_list_like(names) and level is None and self.nlevels > 1: + elif not is_list_like(names) and level is None and self.nlevels > 1: raise TypeError("Must pass list-like as `names`.") - if is_dict_like(names) and not isinstance(self, ABCMultiIndex): + elif is_dict_like(names) and not isinstance(self, ABCMultiIndex): raise TypeError("Can only pass dict-like as `names` for MultiIndex.") - if is_dict_like(names) and level is not None: - raise TypeError("Can not pass level when passing dict-like as `names`.") + if isinstance(self, ABCMultiIndex) and is_dict_like(names) and level is None: + # Transform dict to list of new names and corresponding levels + level, names_adjusted = [], [] + for i, name in enumerate(self.names): + if name in names.keys(): + level.append(i) + names_adjusted.append(names[name]) + names = names_adjusted if not is_list_like(names): names = [names] @@ -1409,15 +1415,6 @@ def set_names(self, names, level=None, inplace: bool = False): else: idx = self._shallow_copy() - if isinstance(self, ABCMultiIndex) and is_dict_like(names): - # Transform dict to list of new names and corresponding levels - level, names_adjusted = [], [] - for i, name in enumerate(self.names): - if name in names.keys(): - level.append(i) - names_adjusted.append(names[name]) - names = names_adjusted - idx._set_names(names, level=level) if not inplace: return idx diff --git a/pandas/tests/indexes/multi/test_names.py b/pandas/tests/indexes/multi/test_names.py index 57a89b1ae6d5e..745ed8644ecc6 100644 --- a/pandas/tests/indexes/multi/test_names.py +++ b/pandas/tests/indexes/multi/test_names.py @@ -172,12 +172,6 @@ def test_name_mi_with_dict_like(func, rename_dict, exp_names): def test_name_with_dict_like_raising(): # GH#20421 - mi = MultiIndex.from_arrays([[1, 2], [3, 4]], names=["x", "y"]) - - msg = "Can not pass level when passing dict-like as `names`." - with pytest.raises(TypeError, match=msg): - mi.set_names({"x": "z"}, level=[0, 1]) - ix = pd.Index([1, 2]) msg = "Can only pass dict-like as `names` for MultiIndex." with pytest.raises(TypeError, match=msg): From dd49505b233c6ad367008539c76c43e1a60fda6e Mon Sep 17 00:00:00 2001 From: phofl Date: Wed, 2 Dec 2020 23:30:06 +0100 Subject: [PATCH 09/14] Add tests --- pandas/tests/indexes/multi/test_names.py | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/pandas/tests/indexes/multi/test_names.py b/pandas/tests/indexes/multi/test_names.py index 745ed8644ecc6..185e534ce8d63 100644 --- a/pandas/tests/indexes/multi/test_names.py +++ b/pandas/tests/indexes/multi/test_names.py @@ -170,6 +170,24 @@ def test_name_mi_with_dict_like(func, rename_dict, exp_names): tm.assert_index_equal(result, expected) +@pytest.mark.parametrize("func", ["rename", "set_names"]) +@pytest.mark.parametrize( + "rename_dict, exp_names", + [ + ({"x": "z"}, ["z", "y"]), + ({"x": "z", "y": "x"}, ["z", "x"]), + ({"a": "z"}, ["x", "y"]), + ({}, ["x", "y"]), + ], +) +def test_name_mi_with_dict_like(func, rename_dict, exp_names): + # GH#20421 + mi = MultiIndex.from_arrays([[1, 2], [3, 4]], names=["x", "y"]) + result = getattr(mi, func)(rename_dict) + expected = MultiIndex.from_arrays([[1, 2], [3, 4]], names=exp_names) + tm.assert_index_equal(result, expected) + + def test_name_with_dict_like_raising(): # GH#20421 ix = pd.Index([1, 2]) From b3464278d73d1f50d0b40a7040b80764df4c55b6 Mon Sep 17 00:00:00 2001 From: phofl Date: Wed, 2 Dec 2020 23:37:15 +0100 Subject: [PATCH 10/14] Rename test --- pandas/tests/indexes/multi/test_names.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pandas/tests/indexes/multi/test_names.py b/pandas/tests/indexes/multi/test_names.py index 185e534ce8d63..0000c625d8273 100644 --- a/pandas/tests/indexes/multi/test_names.py +++ b/pandas/tests/indexes/multi/test_names.py @@ -162,7 +162,7 @@ def test_setting_names_from_levels_raises(): ({"y": "z", "a": "b"}, ["x", "z", "x"]), ], ) -def test_name_mi_with_dict_like(func, rename_dict, exp_names): +def test_name_mi_with_dict_like_duplicate_names(func, rename_dict, exp_names): # GH#20421 mi = MultiIndex.from_arrays([[1, 2], [3, 4], [5, 6]], names=["x", "y", "x"]) result = getattr(mi, func)(rename_dict) From 02c7909e5be8a3aabbb713ba61572a46e378b5f2 Mon Sep 17 00:00:00 2001 From: phofl Date: Fri, 11 Dec 2020 18:40:33 +0100 Subject: [PATCH 11/14] Move whatsnew --- doc/source/whatsnew/v1.3.0.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/source/whatsnew/v1.3.0.rst b/doc/source/whatsnew/v1.3.0.rst index d0afc24aaecac..1de28368b3f23 100644 --- a/doc/source/whatsnew/v1.3.0.rst +++ b/doc/source/whatsnew/v1.3.0.rst @@ -19,7 +19,7 @@ Enhancements Other enhancements ^^^^^^^^^^^^^^^^^^ -- +- Add support for dict-like names in :class:`MultiIndex.set_names` and :class:`MultiIndex.rename` (:issue:`20421`) - .. --------------------------------------------------------------------------- From 0f5f6e1df881df6f099cc8af9980cede39ec5934 Mon Sep 17 00:00:00 2001 From: phofl Date: Mon, 4 Jan 2021 13:23:25 +0100 Subject: [PATCH 12/14] Adjust doc --- pandas/core/indexes/base.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pandas/core/indexes/base.py b/pandas/core/indexes/base.py index 9f71f6fbb7419..ba09d80f7b550 100644 --- a/pandas/core/indexes/base.py +++ b/pandas/core/indexes/base.py @@ -1389,7 +1389,7 @@ def set_names(self, names, level=None, inplace: bool = False): If the index is a MultiIndex and names is not dict-like, level(s) to set (None for all levels). Otherwise level must be None. - .. versionchanged:: 1.2.0 + .. versionchanged:: 1.3.0 inplace : bool, default False Modifies the object directly, instead of creating a new Index or @@ -1434,7 +1434,7 @@ def set_names(self, names, level=None, inplace: bool = False): ( 'cobra', 2019)], names=['species', 'year']) - When renaming levels through a dictionary no level can't be passed. + When renaming levels with a dict, levels can not be passed. >>> idx.set_names({'kind': 'snake'}) MultiIndex([('python', 2018), From b4767d265b779dbde456ad20a16d5d0b982a4849 Mon Sep 17 00:00:00 2001 From: phofl Date: Mon, 4 Jan 2021 13:29:37 +0100 Subject: [PATCH 13/14] Add test and add condition --- pandas/core/indexes/base.py | 3 +++ pandas/tests/indexes/multi/test_names.py | 9 ++++++++- 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/pandas/core/indexes/base.py b/pandas/core/indexes/base.py index ba09d80f7b550..fee946602f42e 100644 --- a/pandas/core/indexes/base.py +++ b/pandas/core/indexes/base.py @@ -1455,6 +1455,9 @@ def set_names(self, names, level=None, inplace: bool = False): elif is_dict_like(names) and not isinstance(self, ABCMultiIndex): raise TypeError("Can only pass dict-like as `names` for MultiIndex.") + elif is_dict_like(names) and level is not None: + raise TypeError("Can not pass level for dictlike `names`.") + if isinstance(self, ABCMultiIndex) and is_dict_like(names) and level is None: # Transform dict to list of new names and corresponding levels level, names_adjusted = [], [] diff --git a/pandas/tests/indexes/multi/test_names.py b/pandas/tests/indexes/multi/test_names.py index 316cb83da655a..de7d2b4410d42 100644 --- a/pandas/tests/indexes/multi/test_names.py +++ b/pandas/tests/indexes/multi/test_names.py @@ -190,9 +190,16 @@ def test_name_mi_with_dict_like(func, rename_dict, exp_names): tm.assert_index_equal(result, expected) -def test_name_with_dict_like_raising(): +def test_index_name_with_dict_like_raising(): # GH#20421 ix = pd.Index([1, 2]) msg = "Can only pass dict-like as `names` for MultiIndex." with pytest.raises(TypeError, match=msg): ix.set_names({"x": "z"}) + + +def test_multiindex_name_and_level_raising(): + # GH#20421 + mi = MultiIndex.from_arrays([[1, 2], [3, 4]], names=["x", "y"]) + with pytest.raises(TypeError, match="Can not pass level for dictlike `names`."): + mi.set_names(names={"x": "z"}, level={"x": "z"}) From c9f72646cc297e44ae9f2e582ed63ad93124f653 Mon Sep 17 00:00:00 2001 From: phofl Date: Mon, 4 Jan 2021 14:53:49 +0100 Subject: [PATCH 14/14] Change number --- pandas/core/indexes/base.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pandas/core/indexes/base.py b/pandas/core/indexes/base.py index fee946602f42e..37212466f86f0 100644 --- a/pandas/core/indexes/base.py +++ b/pandas/core/indexes/base.py @@ -1383,7 +1383,7 @@ def set_names(self, names, level=None, inplace: bool = False): names : label or list of label or dict-like for MultiIndex Name(s) to set. - .. versionchanged:: 1.2.0 + .. versionchanged:: 1.3.0 level : int, label or list of int or label, optional If the index is a MultiIndex and names is not dict-like, level(s) to set