From c45cdef31b7b838e1b3de9ada6ad491036f2365f Mon Sep 17 00:00:00 2001 From: arw2019 Date: Fri, 5 Jun 2020 04:12:23 +0000 Subject: [PATCH 01/12] BUG: added names arg to MI returned by truncate --- pandas/core/indexes/multi.py | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/pandas/core/indexes/multi.py b/pandas/core/indexes/multi.py index fc2d4cf4621c4..4293fd04a5093 100644 --- a/pandas/core/indexes/multi.py +++ b/pandas/core/indexes/multi.py @@ -3195,7 +3195,12 @@ def truncate(self, before=None, after=None): new_codes = [level_codes[left:right] for level_codes in self.codes] new_codes[0] = new_codes[0] - i - return MultiIndex(levels=new_levels, codes=new_codes, verify_integrity=False) + return MultiIndex( + levels=new_levels, + codes=new_codes, + names=self._names, + verify_integrity=False, + ) def equals(self, other) -> bool: """ From 728c9e402b84ff768ed894edffc48e0ecef02dfd Mon Sep 17 00:00:00 2001 From: arw2019 Date: Fri, 5 Jun 2020 04:13:52 +0000 Subject: [PATCH 02/12] DOC: whatsnew updated with comment on issue #34564 --- doc/source/whatsnew/v1.1.0.rst | 1 + 1 file changed, 1 insertion(+) diff --git a/doc/source/whatsnew/v1.1.0.rst b/doc/source/whatsnew/v1.1.0.rst index 7834e1a5c4898..58c99ac01638c 100644 --- a/doc/source/whatsnew/v1.1.0.rst +++ b/doc/source/whatsnew/v1.1.0.rst @@ -911,6 +911,7 @@ MultiIndex df.loc[(['b', 'a'], [2, 1]), :] - Bug in :meth:`MultiIndex.intersection` was not guaranteed to preserve order when ``sort=False``. (:issue:`31325`) +- Bug in :meth:`DataFrame.truncate` was dropping MultiIndex names. (:issue:`34564`) .. ipython:: python From 17f078c22f353e911763a945e1a795404133bfeb Mon Sep 17 00:00:00 2001 From: Andrew Wieteska <48889395+arw2019@users.noreply.github.com> Date: Fri, 5 Jun 2020 21:44:30 -0400 Subject: [PATCH 03/12] DOC: update doc/source/whatsnew/v1.1.0.rst Co-authored-by: Daniel Saxton <2658661+dsaxton@users.noreply.github.com> --- doc/source/whatsnew/v1.1.0.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/source/whatsnew/v1.1.0.rst b/doc/source/whatsnew/v1.1.0.rst index 58c99ac01638c..5ad6ad73ae550 100644 --- a/doc/source/whatsnew/v1.1.0.rst +++ b/doc/source/whatsnew/v1.1.0.rst @@ -911,7 +911,7 @@ MultiIndex df.loc[(['b', 'a'], [2, 1]), :] - Bug in :meth:`MultiIndex.intersection` was not guaranteed to preserve order when ``sort=False``. (:issue:`31325`) -- Bug in :meth:`DataFrame.truncate` was dropping MultiIndex names. (:issue:`34564`) +- Bug in :meth:`DataFrame.truncate` was dropping :class:`MultiIndex` names. (:issue:`34564`) .. ipython:: python From 025cc5f9f00cb055eb6eb825678eb72925bbb6b4 Mon Sep 17 00:00:00 2001 From: arw2019 Date: Sat, 6 Jun 2020 02:54:39 +0000 Subject: [PATCH 04/12] TST: added test for truncate multiindex level names --- pandas/tests/indexing/multiindex/test_slice.py | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/pandas/tests/indexing/multiindex/test_slice.py b/pandas/tests/indexing/multiindex/test_slice.py index 532bb4f2e6dac..cd1b831b99a6f 100644 --- a/pandas/tests/indexing/multiindex/test_slice.py +++ b/pandas/tests/indexing/multiindex/test_slice.py @@ -744,3 +744,11 @@ def test_non_reducing_slice_on_multiindex(self): result = df.loc[tslice_] expected = pd.DataFrame({("b", "d"): [4, 1]}) tm.assert_frame_equal(result, expected) + + def test_truncate_multiindex_names(self): + # GH 34564 + + mi = pd.MultiIndex.from_product([[1, 2, 3, 4], ["A", "B"]], names=["L1", "L2"]) + s1 = pd.Series(range(mi.shape[0]), index=mi) + s2 = s1.truncate(before=2, after=3) + assert s1.index.names == s2.index.names From a9981d80495896f76d9d03c323142da8dd74724a Mon Sep 17 00:00:00 2001 From: arw2019 Date: Sat, 20 Jun 2020 02:41:17 +0000 Subject: [PATCH 05/12] TST: check MultiIndex names after truncate --- pandas/tests/indexes/multi/test_analytics.py | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/pandas/tests/indexes/multi/test_analytics.py b/pandas/tests/indexes/multi/test_analytics.py index 154ed22214830..6982be228c2cb 100644 --- a/pandas/tests/indexes/multi/test_analytics.py +++ b/pandas/tests/indexes/multi/test_analytics.py @@ -31,6 +31,7 @@ def test_groupby(idx): def test_truncate(): + # GH 34564 for MultiIndex level names check major_axis = Index(list(range(4))) minor_axis = Index(list(range(2))) @@ -38,19 +39,24 @@ def test_truncate(): minor_codes = np.array([0, 1, 0, 1, 0, 1]) index = MultiIndex( - levels=[major_axis, minor_axis], codes=[major_codes, minor_codes] + levels=[major_axis, minor_axis], + codes=[major_codes, minor_codes], + names=["L1", "L2"], ) result = index.truncate(before=1) assert "foo" not in result.levels[0] assert 1 in result.levels[0] + assert index.names == result.names result = index.truncate(after=1) assert 2 not in result.levels[0] assert 1 in result.levels[0] + assert index.names == result.names result = index.truncate(before=1, after=2) assert len(result.levels[0]) == 2 + assert index.names == result.names msg = "after < before" with pytest.raises(ValueError, match=msg): From 1e4f32e659e15922fcb0fdf26f470c177fd4fad5 Mon Sep 17 00:00:00 2001 From: arw2019 Date: Sat, 20 Jun 2020 03:07:23 +0000 Subject: [PATCH 06/12] TST: test truncate for multiindex --- pandas/tests/frame/methods/test_truncate.py | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/pandas/tests/frame/methods/test_truncate.py b/pandas/tests/frame/methods/test_truncate.py index 768a5f22fb063..c118dc6e7bdda 100644 --- a/pandas/tests/frame/methods/test_truncate.py +++ b/pandas/tests/frame/methods/test_truncate.py @@ -104,3 +104,15 @@ def test_truncate_decreasing_index(self, before, after, indices, klass): result = values.truncate(before=before, after=after) expected = values.loc[indices] tm.assert_frame_equal(result, expected) + + def test_truncate_multiindex(self): + mi = pd.MultiIndex.from_product([[1, 2, 3, 4], ["A", "B"]], names=["L1", "L2"]) + s1 = pd.DataFrame(range(mi.shape[0]), index=mi, columns=["col"]) + result = s1.truncate(before=2, after=3) + + df = pd.DataFrame.from_dict( + {"L1": [2, 2, 3, 3], "L2": ["A", "B", "A", "B"], "col": [2, 3, 4, 5]} + ) + expected = df.set_index(["L1", "L2"]) + + tm.assert_frame_equal(result, expected) From 50a66f1e30a6eb8333709953fad423592d653d3a Mon Sep 17 00:00:00 2001 From: arw2019 Date: Sat, 20 Jun 2020 03:16:52 +0000 Subject: [PATCH 07/12] TST: test truncate for multiindexed series --- pandas/tests/series/methods/test_truncate.py | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/pandas/tests/series/methods/test_truncate.py b/pandas/tests/series/methods/test_truncate.py index 47947f0287494..e4db381d5200e 100644 --- a/pandas/tests/series/methods/test_truncate.py +++ b/pandas/tests/series/methods/test_truncate.py @@ -126,3 +126,16 @@ def test_truncate_periodindex(self): expected_idx2 = pd.PeriodIndex([pd.Period("2017-09-02")]) tm.assert_series_equal(result2, pd.Series([2], index=expected_idx2)) + + def test_truncate_multiindex(self): + mi = pd.MultiIndex.from_product([[1, 2, 3, 4], ["A", "B"]], names=["L1", "L2"]) + s1 = pd.Series(range(mi.shape[0]), index=mi) + result = s1.truncate(before=2, after=3) + + df = pd.DataFrame.from_dict( + {"L1": [2, 2, 3, 3], "L2": ["A", "B", "A", "B"], "col": [2, 3, 4, 5]} + ) + df.set_index(["L1", "L2"], inplace=True) + expected = df.col + + tm.assert_series_equal(result, expected) From 8efac79c8cbeb90523f1d56fb93c7001c687f3c8 Mon Sep 17 00:00:00 2001 From: arw2019 Date: Sat, 20 Jun 2020 03:57:00 +0000 Subject: [PATCH 08/12] TST: fixed name in test truncate for MI --- pandas/tests/series/methods/test_truncate.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pandas/tests/series/methods/test_truncate.py b/pandas/tests/series/methods/test_truncate.py index e4db381d5200e..206640d1e288e 100644 --- a/pandas/tests/series/methods/test_truncate.py +++ b/pandas/tests/series/methods/test_truncate.py @@ -129,7 +129,7 @@ def test_truncate_periodindex(self): def test_truncate_multiindex(self): mi = pd.MultiIndex.from_product([[1, 2, 3, 4], ["A", "B"]], names=["L1", "L2"]) - s1 = pd.Series(range(mi.shape[0]), index=mi) + s1 = pd.Series(range(mi.shape[0]), index=mi, name="col") result = s1.truncate(before=2, after=3) df = pd.DataFrame.from_dict( From 982d96ebf3926cfedba7d9619bdfff8cdb2740f6 Mon Sep 17 00:00:00 2001 From: arw2019 Date: Sat, 20 Jun 2020 17:24:11 +0000 Subject: [PATCH 09/12] TST: added issue number to test_truncate_multiindex --- pandas/tests/frame/methods/test_truncate.py | 1 + 1 file changed, 1 insertion(+) diff --git a/pandas/tests/frame/methods/test_truncate.py b/pandas/tests/frame/methods/test_truncate.py index c118dc6e7bdda..674f482c478a0 100644 --- a/pandas/tests/frame/methods/test_truncate.py +++ b/pandas/tests/frame/methods/test_truncate.py @@ -106,6 +106,7 @@ def test_truncate_decreasing_index(self, before, after, indices, klass): tm.assert_frame_equal(result, expected) def test_truncate_multiindex(self): + # GH 34564 mi = pd.MultiIndex.from_product([[1, 2, 3, 4], ["A", "B"]], names=["L1", "L2"]) s1 = pd.DataFrame(range(mi.shape[0]), index=mi, columns=["col"]) result = s1.truncate(before=2, after=3) From 12feb006e957f4c7bbdf03f7515bd47066e7fd3b Mon Sep 17 00:00:00 2001 From: arw2019 Date: Sat, 20 Jun 2020 17:27:03 +0000 Subject: [PATCH 10/12] TST: renamed test_truncate_multiindex --- pandas/tests/indexes/multi/test_analytics.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pandas/tests/indexes/multi/test_analytics.py b/pandas/tests/indexes/multi/test_analytics.py index 6982be228c2cb..9e4e73e793bac 100644 --- a/pandas/tests/indexes/multi/test_analytics.py +++ b/pandas/tests/indexes/multi/test_analytics.py @@ -30,7 +30,7 @@ def test_groupby(idx): tm.assert_dict_equal(groups, exp) -def test_truncate(): +def test_truncate_multiindex(): # GH 34564 for MultiIndex level names check major_axis = Index(list(range(4))) minor_axis = Index(list(range(2))) From e057ed753399f0eef8971596749876c69d6274e9 Mon Sep 17 00:00:00 2001 From: arw2019 Date: Sat, 20 Jun 2020 17:30:18 +0000 Subject: [PATCH 11/12] TST: removed duplicate test --- pandas/tests/indexing/multiindex/test_slice.py | 8 -------- 1 file changed, 8 deletions(-) diff --git a/pandas/tests/indexing/multiindex/test_slice.py b/pandas/tests/indexing/multiindex/test_slice.py index cd1b831b99a6f..532bb4f2e6dac 100644 --- a/pandas/tests/indexing/multiindex/test_slice.py +++ b/pandas/tests/indexing/multiindex/test_slice.py @@ -744,11 +744,3 @@ def test_non_reducing_slice_on_multiindex(self): result = df.loc[tslice_] expected = pd.DataFrame({("b", "d"): [4, 1]}) tm.assert_frame_equal(result, expected) - - def test_truncate_multiindex_names(self): - # GH 34564 - - mi = pd.MultiIndex.from_product([[1, 2, 3, 4], ["A", "B"]], names=["L1", "L2"]) - s1 = pd.Series(range(mi.shape[0]), index=mi) - s2 = s1.truncate(before=2, after=3) - assert s1.index.names == s2.index.names From 9f3e3ac0e7b05a0eb7423795dd7e77f40c196102 Mon Sep 17 00:00:00 2001 From: arw2019 Date: Sat, 20 Jun 2020 17:32:40 +0000 Subject: [PATCH 12/12] TST: added GH issue to test_truncate_multiindex --- pandas/tests/series/methods/test_truncate.py | 1 + 1 file changed, 1 insertion(+) diff --git a/pandas/tests/series/methods/test_truncate.py b/pandas/tests/series/methods/test_truncate.py index 206640d1e288e..8a2c62cee7e24 100644 --- a/pandas/tests/series/methods/test_truncate.py +++ b/pandas/tests/series/methods/test_truncate.py @@ -128,6 +128,7 @@ def test_truncate_periodindex(self): tm.assert_series_equal(result2, pd.Series([2], index=expected_idx2)) def test_truncate_multiindex(self): + # GH 34564 mi = pd.MultiIndex.from_product([[1, 2, 3, 4], ["A", "B"]], names=["L1", "L2"]) s1 = pd.Series(range(mi.shape[0]), index=mi, name="col") result = s1.truncate(before=2, after=3)