diff --git a/doc/source/whatsnew/v0.20.0.txt b/doc/source/whatsnew/v0.20.0.txt index 7fa9991138fba..99d0e063a28df 100644 --- a/doc/source/whatsnew/v0.20.0.txt +++ b/doc/source/whatsnew/v0.20.0.txt @@ -29,6 +29,7 @@ New features Other enhancements ^^^^^^^^^^^^^^^^^^ +- ``Series.sort_index`` accepts parameters ``kind`` and ``na_position`` (:issue:`13589`, :issue:`14444`) diff --git a/pandas/core/generic.py b/pandas/core/generic.py index 697438df87d4f..98bc00a8e7e0d 100644 --- a/pandas/core/generic.py +++ b/pandas/core/generic.py @@ -2029,7 +2029,8 @@ def sort_values(self, by, axis=0, ascending=True, inplace=False, DataFrames, this option is only applied when sorting on a single column or label. na_position : {'first', 'last'}, default 'last' - `first` puts NaNs at the beginning, `last` puts NaNs at the end + `first` puts NaNs at the beginning, `last` puts NaNs at the end. + Not implemented for MultiIndex. sort_remaining : bool, default True if true and sorting by level and index is multilevel, sort by other levels too (in order) after sorting by specified level diff --git a/pandas/core/series.py b/pandas/core/series.py index 1c6b13885dd01..4e0df4fdacc4f 100644 --- a/pandas/core/series.py +++ b/pandas/core/series.py @@ -1773,7 +1773,7 @@ def _try_kind_sort(arr): @Appender(generic._shared_docs['sort_index'] % _shared_doc_kwargs) def sort_index(self, axis=0, level=None, ascending=True, inplace=False, - sort_remaining=True): + kind='quicksort', na_position='last', sort_remaining=True): axis = self._get_axis_number(axis) index = self.index @@ -1783,11 +1783,13 @@ def sort_index(self, axis=0, level=None, ascending=True, inplace=False, elif isinstance(index, MultiIndex): from pandas.core.groupby import _lexsort_indexer indexer = _lexsort_indexer(index.labels, orders=ascending) - indexer = _ensure_platform_int(indexer) - new_index = index.take(indexer) else: - new_index, indexer = index.sort_values(return_indexer=True, - ascending=ascending) + from pandas.core.groupby import _nargsort + indexer = _nargsort(index, kind=kind, ascending=ascending, + na_position=na_position) + + indexer = _ensure_platform_int(indexer) + new_index = index.take(indexer) new_values = self._values.take(indexer) result = self._constructor(new_values, index=new_index) diff --git a/pandas/tests/series/test_sorting.py b/pandas/tests/series/test_sorting.py index 826201adbdb50..69e70c15cae50 100644 --- a/pandas/tests/series/test_sorting.py +++ b/pandas/tests/series/test_sorting.py @@ -144,3 +144,28 @@ def test_sort_index_multiindex(self): # rows share same level='A': sort has no effect without remaining lvls res = s.sort_index(level='A', sort_remaining=False) assert_series_equal(s, res) + + def test_sort_index_kind(self): + # GH #14444 & #13589: Add support for sort algo choosing + series = Series(index=[3, 2, 1, 4, 3]) + expected_series = Series(index=[1, 2, 3, 3, 4]) + + index_sorted_series = series.sort_index(kind='mergesort') + assert_series_equal(expected_series, index_sorted_series) + + index_sorted_series = series.sort_index(kind='quicksort') + assert_series_equal(expected_series, index_sorted_series) + + index_sorted_series = series.sort_index(kind='heapsort') + assert_series_equal(expected_series, index_sorted_series) + + def test_sort_index_na_position(self): + series = Series(index=[3, 2, 1, 4, 3, np.nan]) + + expected_series_first = Series(index=[np.nan, 1, 2, 3, 3, 4]) + index_sorted_series = series.sort_index(na_position='first') + assert_series_equal(expected_series_first, index_sorted_series) + + expected_series_last = Series(index=[1, 2, 3, 3, 4, np.nan]) + index_sorted_series = series.sort_index(na_position='last') + assert_series_equal(expected_series_last, index_sorted_series)