From a12da2c86bc6b8a7f8f9b5016eb3e6abb4dde1b7 Mon Sep 17 00:00:00 2001 From: jreback Date: Fri, 9 Aug 2013 09:40:28 -0400 Subject: [PATCH] BUG: GH4516 Fixed issue with sorting a duplicate multi-index that has multiple dtypes --- doc/source/release.rst | 1 + pandas/core/frame.py | 9 ++++++--- pandas/core/index.py | 13 +++++++++++-- pandas/tests/test_multilevel.py | 12 ++++++++++++ 4 files changed, 30 insertions(+), 5 deletions(-) diff --git a/doc/source/release.rst b/doc/source/release.rst index 95ce03a858570..769b47b18db08 100644 --- a/doc/source/release.rst +++ b/doc/source/release.rst @@ -135,6 +135,7 @@ pandas 0.13 - Raise on set indexing with a Panel and a Panel as a value which needs alignment (:issue:`3777`) - frozenset objects now raise in the ``Series`` constructor (:issue:`4482`, :issue:`4480`) + - Fixed issue with sorting a duplicate multi-index that has multiple dtypes (:issue:`4516`) pandas 0.12 =========== diff --git a/pandas/core/frame.py b/pandas/core/frame.py index 902a6c736b569..0f3bcb32f7287 100644 --- a/pandas/core/frame.py +++ b/pandas/core/frame.py @@ -3304,10 +3304,13 @@ def sortlevel(self, level=0, axis=0, ascending=True, inplace=False): new_axis, indexer = the_axis.sortlevel(level, ascending=ascending) if self._is_mixed_type and not inplace: - if axis == 0: - return self.reindex(index=new_axis) + ax = 'index' if axis == 0 else 'columns' + + if new_axis.is_unique: + d = { ax : new_axis } else: - return self.reindex(columns=new_axis) + d = { ax : indexer, 'takeable' : True } + return self.reindex(**d) if inplace: if axis == 1: diff --git a/pandas/core/index.py b/pandas/core/index.py index 5175e01d116c0..33ea4d25bc7dc 100644 --- a/pandas/core/index.py +++ b/pandas/core/index.py @@ -2165,8 +2165,17 @@ def reindex(self, target, method=None, level=None, limit=None, if self.equals(target): indexer = None else: - indexer = self.get_indexer(target, method=method, - limit=limit) + if self.is_unique: + indexer = self.get_indexer(target, method=method, + limit=limit) + else: + if takeable: + if method is not None or limit is not None: + raise ValueError("cannot do a takeable reindex with " + "with a method or limit") + return self[target], target + + raise Exception("cannot handle a non-takeable non-unique multi-index!") if not isinstance(target, MultiIndex): if indexer is None: diff --git a/pandas/tests/test_multilevel.py b/pandas/tests/test_multilevel.py index d54fc32b6efa6..7379bf5d148dc 100644 --- a/pandas/tests/test_multilevel.py +++ b/pandas/tests/test_multilevel.py @@ -1828,6 +1828,18 @@ def test_duplicate_groupby_issues(self): result = s.groupby(s.index).first() self.assertEquals(len(result), 3) + def test_duplicate_mi(self): + # GH 4516 + df = DataFrame([['foo','bar',1.0,1],['foo','bar',2.0,2],['bah','bam',3.0,3], + ['bah','bam',4.0,4],['foo','bar',5.0,5],['bah','bam',6.0,6]], + columns=list('ABCD')) + df = df.set_index(['A','B']) + df = df.sortlevel(0) + result = df.loc[('foo','bar')] + expected = DataFrame([['foo','bar',1.0,1],['foo','bar',2.0,2],['foo','bar',5.0,5]], + columns=list('ABCD')).set_index(['A','B']) + assert_frame_equal(result,expected) + def test_multiindex_set_index(self): # segfault in #3308 d = {'t1': [2, 2.5, 3], 't2': [4, 5, 6]}