From a590386585b565394b0fca25b621f39a6ff4b4f7 Mon Sep 17 00:00:00 2001 From: Trent Hauck Date: Mon, 15 Feb 2016 23:15:03 -0800 Subject: [PATCH] BUG: Fix bug where sort_index if unsorted levels. Closes #12261 --- doc/source/whatsnew/v0.18.0.txt | 1 + pandas/core/frame.py | 2 +- pandas/tests/frame/test_sorting.py | 15 +++++++++++++++ 3 files changed, 17 insertions(+), 1 deletion(-) diff --git a/doc/source/whatsnew/v0.18.0.txt b/doc/source/whatsnew/v0.18.0.txt index 51ff9915fc589..f345c3d822b3e 100644 --- a/doc/source/whatsnew/v0.18.0.txt +++ b/doc/source/whatsnew/v0.18.0.txt @@ -992,3 +992,4 @@ Bug Fixes - Bug in ``crosstab`` where arguments with non-overlapping indexes would return a ``KeyError`` (:issue:`10291`) - Bug in ``DataFrame.apply`` in which reduction was not being prevented for cases in which ``dtype`` was not a numpy dtype (:issue:`12244`) +- Bug in ``MultiIndex.sort_index`` where if the levels were out of order, but the labels were monotonic, then the index would return unsorted. (:issue:`12261`) diff --git a/pandas/core/frame.py b/pandas/core/frame.py index 8a3ac4db37d2d..1463034f38769 100644 --- a/pandas/core/frame.py +++ b/pandas/core/frame.py @@ -3236,7 +3236,7 @@ def sort_index(self, axis=0, level=None, ascending=True, inplace=False, # make sure that the axis is lexsorted to start # if not we need to reconstruct to get the correct indexer - if not labels.is_lexsorted(): + if not labels.is_lexsorted() or not all([labels.get_level_values(i).is_monotonic for i in range(labels.nlevels)]): labels = MultiIndex.from_tuples(labels.values) indexer = _lexsort_indexer(labels.labels, orders=ascending, diff --git a/pandas/tests/frame/test_sorting.py b/pandas/tests/frame/test_sorting.py index ff2159f8b6f40..86542c08dccef 100644 --- a/pandas/tests/frame/test_sorting.py +++ b/pandas/tests/frame/test_sorting.py @@ -471,3 +471,18 @@ def test_frame_column_inplace_sort_exception(self): cp = s.copy() cp.sort_values() # it works! + + def test_sort_added_index(self): + # GH 12261 + df = DataFrame(0, columns=[], index=MultiIndex.from_product([[], []])) + + df.loc['b', '2'] = 1 + df.loc['a', '3'] = 1 + + expected = DataFrame([[1.0, np.nan], [np.nan, 1.0]], + index=MultiIndex.from_product([['b', 'a'], ['']]), + columns=['2', '3']).sort_index() + + actual = df.sort_index() + + assert_frame_equal(expected, actual)