Skip to content

Commit 186c814

Browse files
committed
BUG: Fix Series.sort_values descending & mergesort
The solution uses the `nargsort` function, which was created to handle in one place the intricacies of sorting. Not adapting Series.sort_values to use may have been an oversight. closes #28697
1 parent ad3280e commit 186c814

File tree

3 files changed

+14
-34
lines changed

3 files changed

+14
-34
lines changed

doc/source/whatsnew/v0.25.2.rst

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,9 @@ Other
102102
- Compatibility with Python 3.8 in :meth:`DataFrame.query` (:issue:`27261`)
103103
- Fix to ensure that tab-completion in an IPython console does not raise
104104
warnings for deprecated attributes (:issue:`27900`).
105+
- Bug in :meth:`Series.sort_values` when ``ascending`` is set to ``False`` and
106+
``kind`` is set to ``mergesort`` (:issue:`28697`)
107+
105108

106109
.. _whatsnew_0.252.contributors:
107110

pandas/core/series.py

Lines changed: 5 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,7 @@
7575
from pandas.core.indexes.timedeltas import TimedeltaIndex
7676
from pandas.core.indexing import check_bool_indexer
7777
from pandas.core.internals import SingleBlockManager
78+
from pandas.core.sorting import nargsort
7879
from pandas.core.strings import StringMethods
7980
from pandas.core.tools.datetimes import to_datetime
8081

@@ -3066,26 +3067,6 @@ def sort_values(
30663067
"sort in-place you must create a copy"
30673068
)
30683069

3069-
def _try_kind_sort(arr):
3070-
# easier to ask forgiveness than permission
3071-
try:
3072-
# if kind==mergesort, it can fail for object dtype
3073-
return arr.argsort(kind=kind)
3074-
except TypeError:
3075-
# stable sort not available for object dtype
3076-
# uses the argsort default quicksort
3077-
return arr.argsort(kind="quicksort")
3078-
3079-
arr = self._values
3080-
sortedIdx = np.empty(len(self), dtype=np.int32)
3081-
3082-
bad = isna(arr)
3083-
3084-
good = ~bad
3085-
idx = ibase.default_index(len(self))
3086-
3087-
argsorted = _try_kind_sort(arr[good])
3088-
30893070
if is_list_like(ascending):
30903071
if len(ascending) != 1:
30913072
raise ValueError(
@@ -3097,21 +3078,11 @@ def _try_kind_sort(arr):
30973078
if not is_bool(ascending):
30983079
raise ValueError("ascending must be boolean")
30993080

3100-
if not ascending:
3101-
argsorted = argsorted[::-1]
3102-
3103-
if na_position == "last":
3104-
n = good.sum()
3105-
sortedIdx[:n] = idx[good][argsorted]
3106-
sortedIdx[n:] = idx[bad]
3107-
elif na_position == "first":
3108-
n = bad.sum()
3109-
sortedIdx[n:] = idx[good][argsorted]
3110-
sortedIdx[:n] = idx[bad]
3111-
else:
3112-
raise ValueError("invalid na_position: {!r}".format(na_position))
3081+
indexer = nargsort(
3082+
self._values, kind=kind, ascending=ascending, na_position=na_position
3083+
)
31133084

3114-
result = self._constructor(arr[sortedIdx], index=self.index[sortedIdx])
3085+
result = self._constructor(self.iloc[indexer], index=self.index[indexer])
31153086

31163087
if inplace:
31173088
self._update_inplace(result)

pandas/tests/series/test_sorting.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,12 @@ def test_sort_values(self):
8686
with pytest.raises(ValueError, match=msg):
8787
s.sort_values(inplace=True)
8888

89+
# mergesort and ascending=False
90+
ser = Series([1, 2, 1, 3], ["first", "b", "second", "c"])
91+
expected = Series([3, 2, 1, 1], ["c", "b", "first", "second"])
92+
result = ser.sort_values(ascending=False, kind="mergesort")
93+
tm.assert_series_equal(expected, result)
94+
8995
def test_sort_index(self):
9096
rindex = list(self.ts.index)
9197
random.shuffle(rindex)

0 commit comments

Comments
 (0)