From 7db707a787e46c5cd3338cc6bb86a32cce73c901 Mon Sep 17 00:00:00 2001 From: wojtek2kdev Date: Mon, 20 Sep 2021 04:56:56 +0000 Subject: [PATCH 01/12] bug: reproduce #43659 in test_rename_with_multiindex at Series test. --- pandas/tests/generic/test_series.py | 31 +++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/pandas/tests/generic/test_series.py b/pandas/tests/generic/test_series.py index b733957cb9170..262f1dd9b44d0 100644 --- a/pandas/tests/generic/test_series.py +++ b/pandas/tests/generic/test_series.py @@ -151,3 +151,34 @@ def finalize(self, other, method=None, **kwargs): # reset Series._metadata = _metadata Series.__finalize__ = _finalize # FIXME: use monkeypatch + + # issue #43659 + def test_rename_with_multiindex(self): + arrays = [ + ["bar", "bar", "baz", "baz", "foo", "foo", "qux", "qux"], + ["one", "two", "one", "two", "one", "two", "one", "two"] + ] + + tuples = list(zip(*arrays)) + index = MultiIndex.from_tuples(tuples, names=["first", "second"]) + s = Series(np.ones(8), index=index) + s.rename(index={'one': 'yes'}, level='second', errors='raise') + + arrays_expected = [ + ["bar", "bar", "baz", "baz", "foo", "foo", "qux", "qux"], + ["yes", "two", "yes", "two", "yes", "two", "yes", "two"] + ] + + tuples_expected = list(zip(*arrays_expected)) + index_expected = MultiIndex.from_tuples( + tuples_expected, + names=["first", "second"] + ) + s_expected = Series(np.ones(8), index=index_expected) + + assert s == s_expected + + + + + From 712c7aa5df8ba1eb8ea152d606aed88780c6f316 Mon Sep 17 00:00:00 2001 From: wojtek2kdev Date: Mon, 20 Sep 2021 05:51:29 +0000 Subject: [PATCH 02/12] test: correct series equality for assertion. --- pandas/tests/generic/test_series.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/pandas/tests/generic/test_series.py b/pandas/tests/generic/test_series.py index 262f1dd9b44d0..961a98ce47902 100644 --- a/pandas/tests/generic/test_series.py +++ b/pandas/tests/generic/test_series.py @@ -162,7 +162,7 @@ def test_rename_with_multiindex(self): tuples = list(zip(*arrays)) index = MultiIndex.from_tuples(tuples, names=["first", "second"]) s = Series(np.ones(8), index=index) - s.rename(index={'one': 'yes'}, level='second', errors='raise') + result = s.rename(index={"one": "yes"}, level='second', errors='raise') arrays_expected = [ ["bar", "bar", "baz", "baz", "foo", "foo", "qux", "qux"], @@ -174,9 +174,9 @@ def test_rename_with_multiindex(self): tuples_expected, names=["first", "second"] ) - s_expected = Series(np.ones(8), index=index_expected) + series_expected = Series(np.ones(8), index=index_expected) - assert s == s_expected + assert result.equals(series_expected) From 5534697c910a435e047524bbbe50a2a22a79e1e7 Mon Sep 17 00:00:00 2001 From: wojtek2kdev Date: Mon, 20 Sep 2021 05:55:21 +0000 Subject: [PATCH 03/12] bug: Add get_indexer_for on MultiIndex on given level. --- pandas/core/generic.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/pandas/core/generic.py b/pandas/core/generic.py index 5c4f24f2d2aac..0dc512bb061ad 100644 --- a/pandas/core/generic.py +++ b/pandas/core/generic.py @@ -1147,7 +1147,11 @@ def rename( # GH 13473 if not callable(replacements): - indexer = ax.get_indexer_for(replacements) + if ax._is_multi: + indexer = ax.get_level_values(level).get_indexer_for(replacements) + else: + indexer = ax.get_indexer_for(replacements) + if errors == "raise" and len(indexer[indexer == -1]): missing_labels = [ label From 3aa23ed98c18ea90ec53847b7aeeaa4e90704539 Mon Sep 17 00:00:00 2001 From: wojtek2kdev Date: Mon, 20 Sep 2021 18:34:50 +0000 Subject: [PATCH 04/12] lint: correction lint errors. --- pandas/tests/generic/test_series.py | 14 ++++---------- 1 file changed, 4 insertions(+), 10 deletions(-) diff --git a/pandas/tests/generic/test_series.py b/pandas/tests/generic/test_series.py index 961a98ce47902..2647f2a8de642 100644 --- a/pandas/tests/generic/test_series.py +++ b/pandas/tests/generic/test_series.py @@ -156,29 +156,23 @@ def finalize(self, other, method=None, **kwargs): def test_rename_with_multiindex(self): arrays = [ ["bar", "bar", "baz", "baz", "foo", "foo", "qux", "qux"], - ["one", "two", "one", "two", "one", "two", "one", "two"] + ["one", "two", "one", "two", "one", "two", "one", "two"], ] tuples = list(zip(*arrays)) index = MultiIndex.from_tuples(tuples, names=["first", "second"]) s = Series(np.ones(8), index=index) - result = s.rename(index={"one": "yes"}, level='second', errors='raise') + result = s.rename(index={"one": "yes"}, level="second", errors="raise") arrays_expected = [ ["bar", "bar", "baz", "baz", "foo", "foo", "qux", "qux"], - ["yes", "two", "yes", "two", "yes", "two", "yes", "two"] + ["yes", "two", "yes", "two", "yes", "two", "yes", "two"], ] tuples_expected = list(zip(*arrays_expected)) index_expected = MultiIndex.from_tuples( - tuples_expected, - names=["first", "second"] + tuples_expected, names=["first", "second"] ) series_expected = Series(np.ones(8), index=index_expected) assert result.equals(series_expected) - - - - - From cdf3013a83ab75203cd9c289d20f3a14fd8cc135 Mon Sep 17 00:00:00 2001 From: wojtek2kdev Date: Mon, 20 Sep 2021 18:37:10 +0000 Subject: [PATCH 05/12] bug(NDFrame): indexer for MultiIndex only if level is provided. --- pandas/core/generic.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pandas/core/generic.py b/pandas/core/generic.py index 0dc512bb061ad..bb19438793482 100644 --- a/pandas/core/generic.py +++ b/pandas/core/generic.py @@ -1147,11 +1147,11 @@ def rename( # GH 13473 if not callable(replacements): - if ax._is_multi: + if ax._is_multi and level is not None: indexer = ax.get_level_values(level).get_indexer_for(replacements) else: indexer = ax.get_indexer_for(replacements) - + if errors == "raise" and len(indexer[indexer == -1]): missing_labels = [ label From 0c74b1f22daa05d8fc281976b5f95277599aa5ce Mon Sep 17 00:00:00 2001 From: wojtek2kdev Date: Mon, 20 Sep 2021 19:40:29 +0000 Subject: [PATCH 06/12] test(test_series): Simplify test_rename_with_multiindex. --- pandas/tests/generic/test_series.py | 20 +++++++++----------- 1 file changed, 9 insertions(+), 11 deletions(-) diff --git a/pandas/tests/generic/test_series.py b/pandas/tests/generic/test_series.py index 2647f2a8de642..49f8a998e9110 100644 --- a/pandas/tests/generic/test_series.py +++ b/pandas/tests/generic/test_series.py @@ -155,24 +155,22 @@ def finalize(self, other, method=None, **kwargs): # issue #43659 def test_rename_with_multiindex(self): arrays = [ - ["bar", "bar", "baz", "baz", "foo", "foo", "qux", "qux"], - ["one", "two", "one", "two", "one", "two", "one", "two"], + ["bar", "baz", "baz", "foo", "qux"], + ["one", "one", "two", "two", "one"], ] - tuples = list(zip(*arrays)) - index = MultiIndex.from_tuples(tuples, names=["first", "second"]) - s = Series(np.ones(8), index=index) + index = MultiIndex.from_arrays(arrays, names=["first", "second"]) + s = Series(np.ones(5), index=index) result = s.rename(index={"one": "yes"}, level="second", errors="raise") arrays_expected = [ - ["bar", "bar", "baz", "baz", "foo", "foo", "qux", "qux"], - ["yes", "two", "yes", "two", "yes", "two", "yes", "two"], + ["bar", "baz", "baz", "foo", "qux"], + ["yes", "yes", "two", "two", "yes"], ] - tuples_expected = list(zip(*arrays_expected)) - index_expected = MultiIndex.from_tuples( - tuples_expected, names=["first", "second"] + index_expected = MultiIndex.from_arrays( + arrays_expected, names=["first", "second"] ) - series_expected = Series(np.ones(8), index=index_expected) + series_expected = Series(np.ones(5), index=index_expected) assert result.equals(series_expected) From 2c9f511a446b3954241d93ef2fc847e93c13d4c6 Mon Sep 17 00:00:00 2001 From: wojtek2kdev Date: Mon, 20 Sep 2021 19:41:32 +0000 Subject: [PATCH 07/12] test(test_series): Move reference to issue into test. --- pandas/tests/generic/test_series.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pandas/tests/generic/test_series.py b/pandas/tests/generic/test_series.py index 49f8a998e9110..2f1471e3e9fb5 100644 --- a/pandas/tests/generic/test_series.py +++ b/pandas/tests/generic/test_series.py @@ -152,8 +152,8 @@ def finalize(self, other, method=None, **kwargs): Series._metadata = _metadata Series.__finalize__ = _finalize # FIXME: use monkeypatch - # issue #43659 def test_rename_with_multiindex(self): + # issue #43659 arrays = [ ["bar", "baz", "baz", "foo", "qux"], ["one", "one", "two", "two", "one"], From 288344ca7e9fbf3b719cec41473645aa8bd80b9e Mon Sep 17 00:00:00 2001 From: wojtek2kdev Date: Mon, 20 Sep 2021 19:51:23 +0000 Subject: [PATCH 08/12] doc: Resolve bug #43659 --- doc/source/whatsnew/v1.4.0.rst | 1 + 1 file changed, 1 insertion(+) diff --git a/doc/source/whatsnew/v1.4.0.rst b/doc/source/whatsnew/v1.4.0.rst index f18b3b75ca3d2..9acf0b7b884e6 100644 --- a/doc/source/whatsnew/v1.4.0.rst +++ b/doc/source/whatsnew/v1.4.0.rst @@ -413,6 +413,7 @@ Interval Indexing ^^^^^^^^ +- Bug in :meth:`Series.rename` when index in Series is MultiIndex and level in rename is provided. (:issue:`43659`) - Bug in :meth:`DataFrame.truncate` and :meth:`Series.truncate` when the object's Index has a length greater than one but only one unique value (:issue:`42365`) - Bug in :meth:`Series.loc` and :meth:`DataFrame.loc` with a :class:`MultiIndex` when indexing with a tuple in which one of the levels is also a tuple (:issue:`27591`) - Bug in :meth:`Series.loc` when with a :class:`MultiIndex` whose first level contains only ``np.nan`` values (:issue:`42055`) From 191f646fdc9bd2a4a1bf546fdf09fe1ee653ff90 Mon Sep 17 00:00:00 2001 From: wojtek2kdev Date: Wed, 22 Sep 2021 21:45:40 +0000 Subject: [PATCH 09/12] test(rename): Move test related to #43659 into proper file. --- pandas/tests/frame/methods/test_rename.py | 23 +++++++++++++++++++++++ pandas/tests/generic/test_series.py | 23 ----------------------- 2 files changed, 23 insertions(+), 23 deletions(-) diff --git a/pandas/tests/frame/methods/test_rename.py b/pandas/tests/frame/methods/test_rename.py index 462d588aff58f..cbadad971eea8 100644 --- a/pandas/tests/frame/methods/test_rename.py +++ b/pandas/tests/frame/methods/test_rename.py @@ -170,6 +170,29 @@ def test_rename_multiindex(self): renamed = df.rename(index={"foo1": "foo3", "bar2": "bar3"}, level=0) tm.assert_index_equal(renamed.index, new_index) + def test_rename_series_with_multiindex(self): + # issue #43659 + arrays = [ + ["bar", "baz", "baz", "foo", "qux"], + ["one", "one", "two", "two", "one"], + ] + + index = MultiIndex.from_arrays(arrays, names=["first", "second"]) + s = Series(np.ones(5), index=index) + result = s.rename(index={"one": "yes"}, level="second", errors="raise") + + arrays_expected = [ + ["bar", "baz", "baz", "foo", "qux"], + ["yes", "yes", "two", "two", "yes"], + ] + + index_expected = MultiIndex.from_arrays( + arrays_expected, names=["first", "second"] + ) + series_expected = Series(np.ones(5), index=index_expected) + + assert result.equals(series_expected) + @td.skip_array_manager_not_yet_implemented # TODO(ArrayManager) setitem copy/view def test_rename_nocopy(self, float_frame): renamed = float_frame.rename(columns={"C": "foo"}, copy=False) diff --git a/pandas/tests/generic/test_series.py b/pandas/tests/generic/test_series.py index 2f1471e3e9fb5..b733957cb9170 100644 --- a/pandas/tests/generic/test_series.py +++ b/pandas/tests/generic/test_series.py @@ -151,26 +151,3 @@ def finalize(self, other, method=None, **kwargs): # reset Series._metadata = _metadata Series.__finalize__ = _finalize # FIXME: use monkeypatch - - def test_rename_with_multiindex(self): - # issue #43659 - arrays = [ - ["bar", "baz", "baz", "foo", "qux"], - ["one", "one", "two", "two", "one"], - ] - - index = MultiIndex.from_arrays(arrays, names=["first", "second"]) - s = Series(np.ones(5), index=index) - result = s.rename(index={"one": "yes"}, level="second", errors="raise") - - arrays_expected = [ - ["bar", "baz", "baz", "foo", "qux"], - ["yes", "yes", "two", "two", "yes"], - ] - - index_expected = MultiIndex.from_arrays( - arrays_expected, names=["first", "second"] - ) - series_expected = Series(np.ones(5), index=index_expected) - - assert result.equals(series_expected) From eeb2c86da8177e22f4c200b36ac729ce233b94ee Mon Sep 17 00:00:00 2001 From: wojtek2kdev Date: Wed, 22 Sep 2021 19:51:26 +0000 Subject: [PATCH 10/12] Mistake: test moved to frame instead of series. Now its correct. --- pandas/tests/frame/methods/test_rename.py | 23 --------------------- pandas/tests/series/methods/test_rename.py | 24 ++++++++++++++++++++++ 2 files changed, 24 insertions(+), 23 deletions(-) diff --git a/pandas/tests/frame/methods/test_rename.py b/pandas/tests/frame/methods/test_rename.py index cbadad971eea8..462d588aff58f 100644 --- a/pandas/tests/frame/methods/test_rename.py +++ b/pandas/tests/frame/methods/test_rename.py @@ -170,29 +170,6 @@ def test_rename_multiindex(self): renamed = df.rename(index={"foo1": "foo3", "bar2": "bar3"}, level=0) tm.assert_index_equal(renamed.index, new_index) - def test_rename_series_with_multiindex(self): - # issue #43659 - arrays = [ - ["bar", "baz", "baz", "foo", "qux"], - ["one", "one", "two", "two", "one"], - ] - - index = MultiIndex.from_arrays(arrays, names=["first", "second"]) - s = Series(np.ones(5), index=index) - result = s.rename(index={"one": "yes"}, level="second", errors="raise") - - arrays_expected = [ - ["bar", "baz", "baz", "foo", "qux"], - ["yes", "yes", "two", "two", "yes"], - ] - - index_expected = MultiIndex.from_arrays( - arrays_expected, names=["first", "second"] - ) - series_expected = Series(np.ones(5), index=index_expected) - - assert result.equals(series_expected) - @td.skip_array_manager_not_yet_implemented # TODO(ArrayManager) setitem copy/view def test_rename_nocopy(self, float_frame): renamed = float_frame.rename(columns={"C": "foo"}, copy=False) diff --git a/pandas/tests/series/methods/test_rename.py b/pandas/tests/series/methods/test_rename.py index eacafa9310384..7039898c62f7c 100644 --- a/pandas/tests/series/methods/test_rename.py +++ b/pandas/tests/series/methods/test_rename.py @@ -4,6 +4,7 @@ from pandas import ( Index, + MultiIndex, Series, ) import pandas._testing as tm @@ -101,3 +102,26 @@ def test_rename_callable(self): tm.assert_series_equal(result, expected) assert result.name == expected.name + + def test_rename_series_with_multiindex(self): + # issue #43659 + arrays = [ + ["bar", "baz", "baz", "foo", "qux"], + ["one", "one", "two", "two", "one"], + ] + + index = MultiIndex.from_arrays(arrays, names=["first", "second"]) + s = Series(np.ones(5), index=index) + result = s.rename(index={"one": "yes"}, level="second", errors="raise") + + arrays_expected = [ + ["bar", "baz", "baz", "foo", "qux"], + ["yes", "yes", "two", "two", "yes"], + ] + + index_expected = MultiIndex.from_arrays( + arrays_expected, names=["first", "second"] + ) + series_expected = Series(np.ones(5), index=index_expected) + + assert result.equals(series_expected) \ No newline at end of file From 80a556d6a6515d04d9afd33c4b320ee6b5326329 Mon Sep 17 00:00:00 2001 From: wojtek2kdev Date: Wed, 22 Sep 2021 19:52:57 +0000 Subject: [PATCH 11/12] lint: Add newline in test file. --- pandas/tests/series/methods/test_rename.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pandas/tests/series/methods/test_rename.py b/pandas/tests/series/methods/test_rename.py index 7039898c62f7c..e05ccce77c98d 100644 --- a/pandas/tests/series/methods/test_rename.py +++ b/pandas/tests/series/methods/test_rename.py @@ -124,4 +124,4 @@ def test_rename_series_with_multiindex(self): ) series_expected = Series(np.ones(5), index=index_expected) - assert result.equals(series_expected) \ No newline at end of file + assert result.equals(series_expected) From aa1fc34bdc2a226502ba68d701d26801f6a53b40 Mon Sep 17 00:00:00 2001 From: wojtek2kdev Date: Thu, 23 Sep 2021 15:44:50 +0000 Subject: [PATCH 12/12] test(series/rename): Change assertion method. --- pandas/tests/series/methods/test_rename.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pandas/tests/series/methods/test_rename.py b/pandas/tests/series/methods/test_rename.py index e05ccce77c98d..e00e9a894d340 100644 --- a/pandas/tests/series/methods/test_rename.py +++ b/pandas/tests/series/methods/test_rename.py @@ -124,4 +124,4 @@ def test_rename_series_with_multiindex(self): ) series_expected = Series(np.ones(5), index=index_expected) - assert result.equals(series_expected) + tm.assert_series_equal(result, series_expected)