Skip to content

Commit a5d5c6d

Browse files
reverted and updated documentation
1 parent e87a9a9 commit a5d5c6d

File tree

7 files changed

+127
-78
lines changed

7 files changed

+127
-78
lines changed

doc/source/user_guide/basics.rst

+13
Original file line numberDiff line numberDiff line change
@@ -1796,9 +1796,16 @@ the key is applied per-level to the levels specified by `level`.
17961796
"b": [1, 2, 3],
17971797
"c": [2, 3, 4]
17981798
}).set_index(list("ab"))
1799+
s1
1800+
1801+
.. ipython:: python
1802+
17991803
s1.sort_index(level="a")
18001804
s1.sort_index(level="a", key=lambda idx: idx.str.lower())
18011805
1806+
For information on key sorting by value, see :ref:`value sorting
1807+
<basics.sort_value_key>`.
1808+
18021809
.. _basics.sort_values:
18031810

18041811
By values
@@ -1841,6 +1848,9 @@ to apply to the values being sorted.
18411848
.. ipython:: python
18421849
18431850
s1 = pd.Series(['B', 'a', 'C'])
1851+
1852+
.. ipython:: python
1853+
18441854
s1.sort_values()
18451855
s1.sort_values(key=lambda x: x.str.lower())
18461856
@@ -1852,6 +1862,9 @@ a Series, e.g.
18521862
.. ipython:: python
18531863
18541864
df = pd.DataFrame({"a": ['B', 'a', 'C'], "b": [1, 2, 3]})
1865+
1866+
.. ipython:: python
1867+
18551868
df.sort_values(by='a')
18561869
df.sort_values(by='a', key=lambda col: col.str.lower())
18571870

doc/source/whatsnew/v1.1.0.rst

+8
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,10 @@ See :ref:`sort_values with keys <basics.sort_value_key>` and :ref:`sort_index wi
5151
.. ipython:: python
5252
5353
s = pd.Series(['C', 'a', 'B'])
54+
s
55+
56+
.. ipython:: python
57+
5458
s.sort_values()
5559
5660
@@ -69,6 +73,10 @@ When applied to a `DataFrame`, they key is applied per-column to all columns or
6973
7074
df = pd.DataFrame({'a': ['C', 'C', 'a', 'a', 'B', 'B'],
7175
'b': [1, 2, 3, 4, 5, 6]})
76+
df
77+
78+
.. ipython:: python
79+
7280
df.sort_values(by=['a'], key=lambda col: col.str.lower())
7381
7482

pandas/core/indexes/datetimelike.py

+6-24
Original file line numberDiff line numberDiff line change
@@ -175,33 +175,15 @@ def sort_values(self, return_indexer=False, ascending=True, key=None):
175175
"""
176176
idx = ensure_key_mapped(self, key)
177177

178+
_as = idx.argsort()
179+
if not ascending:
180+
_as = _as[::-1]
181+
sorted_index = self.take(_as)
182+
178183
if return_indexer:
179-
_as = idx.argsort()
180-
if not ascending:
181-
_as = _as[::-1]
182-
sorted_index = self.take(_as)
183184
return sorted_index, _as
184185
else:
185-
# NB: using asi8 instead of _data matters in numpy 1.18
186-
# because the treatment of NaT has been changed to put NaT last
187-
# instead of first.
188-
_as = np.argsort(idx.asi8)
189-
sorted_values = self.asi8[_as]
190-
191-
freq = self.freq
192-
if freq is not None and not is_period_dtype(self):
193-
if freq.n > 0 and not ascending:
194-
freq = freq * -1
195-
elif freq.n < 0 and ascending:
196-
freq = freq * -1
197-
198-
if not ascending:
199-
sorted_values = sorted_values[::-1]
200-
201-
arr = type(self._data)._simple_new(
202-
sorted_values, dtype=self.dtype, freq=freq
203-
)
204-
return type(self)._simple_new(arr, name=self.name)
186+
sorted_index
205187

206188
@Appender(_index_shared_docs["take"] % _index_doc_kwargs)
207189
def take(self, indices, axis=0, allow_fill=True, fill_value=None, **kwargs):

pandas/core/sorting.py

+17-7
Original file line numberDiff line numberDiff line change
@@ -382,28 +382,38 @@ def ensure_key_mapped(values, key: Optional[Callable], levels=None):
382382
levels : Optional[List], if values is a MultiIndex, list of levels to
383383
apply the key to.
384384
"""
385+
from pandas.core.indexes.api import Index
386+
385387
if not key:
386388
return values.copy()
387389

388390
if isinstance(values, ABCMultiIndex):
389391
return ensure_key_mapped_multiindex(values, key, level=levels)
390392

391-
type_of_values = type(values)
392393
result = key(values.copy())
393394
if len(result) != len(values):
394395
raise ValueError(
395-
"User-provided `key` function much not change the shape of the array."
396+
"User-provided `key` function must not change the shape of the array."
396397
)
397398

398-
if not isinstance(result, type_of_values): # recover from type error
399-
try:
400-
result = type_of_values(result)
401-
except TypeError:
402-
raise TypeError("User-provided `key` function returned an invalid type.")
399+
try:
400+
if isinstance(values, Index): # allow a new Index class
401+
result = Index(result)
402+
else:
403+
type_of_values = type(values)
404+
result = type_of_values(result) # try to recover otherwise
405+
except TypeError:
406+
raise TypeError(
407+
"User-provided `key` function returned an invalid type {} \
408+
which could not be converted to {}.".format(
409+
type(result), type(values)
410+
)
411+
)
403412

404413
return result
405414

406415

416+
407417
class _KeyMapper:
408418
"""
409419
Map compressed group id -> key tuple.

pandas/tests/frame/methods/test_sort_values.py

+23-1
Original file line numberDiff line numberDiff line change
@@ -630,7 +630,7 @@ def key(col):
630630
expected = df.iloc[[1, 3, 4, 0, 2, 5]]
631631
tm.assert_frame_equal(result, expected)
632632

633-
def test_sort_values_key_nan(self):
633+
def test_sort_values_key_string(self):
634634
df = DataFrame(np.array([["hello", "goodbye"], ["hello", "Hello"]]))
635635

636636
result = df.sort_values(1)
@@ -656,3 +656,25 @@ def test_changes_length_raises(self):
656656
df = pd.DataFrame({"A": [1, 2, 3]})
657657
with pytest.raises(ValueError, match="change the shape"):
658658
df.sort_values("A", key=lambda x: x[:1])
659+
660+
def test_sort_values_key_axes(self):
661+
df = DataFrame({0: ["Hello", "goodbye"], 1: [0, 1]})
662+
663+
result = df.sort_values(0, key=lambda col: col.str.lower())
664+
expected = df[::-1]
665+
tm.assert_frame_equal(result, expected)
666+
667+
result = df.sort_values(1, key=lambda col: -col)
668+
expected = df[::-1]
669+
tm.assert_frame_equal(result, expected)
670+
671+
def test_sort_values_key_dict_axis(self):
672+
df = DataFrame({0: ["Hello", 0], 1: ["goodbye", 1]})
673+
674+
result = df.sort_values(0, key=lambda col: col.str.lower(), axis=1)
675+
expected = df.loc[:, ::-1]
676+
tm.assert_frame_equal(result, expected)
677+
678+
result = df.sort_values(1, key=lambda col: -col, axis=1)
679+
expected = df.loc[:, ::-1]
680+
tm.assert_frame_equal(result, expected)

pandas/tests/series/methods/test_sort_index.py

+60-1
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
import numpy as np
44
import pytest
55

6-
from pandas import IntervalIndex, MultiIndex, Series
6+
from pandas import DatetimeIndex, IntervalIndex, MultiIndex, Series
77
import pandas._testing as tm
88

99

@@ -223,7 +223,66 @@ def test_sort_index_key_int(self):
223223
result = series.sort_index(key=lambda x: 2 * x)
224224
tm.assert_series_equal(result, series)
225225

226+
def test_sort_index_kind_key(self, sort_by_key):
227+
# GH #14444 & #13589: Add support for sort algo choosing
228+
series = Series(index=[3, 2, 1, 4, 3], dtype=object)
229+
expected_series = Series(index=[1, 2, 3, 3, 4], dtype=object)
230+
231+
index_sorted_series = series.sort_index(kind="mergesort", key=sort_by_key)
232+
tm.assert_series_equal(expected_series, index_sorted_series)
233+
234+
index_sorted_series = series.sort_index(kind="quicksort", key=sort_by_key)
235+
tm.assert_series_equal(expected_series, index_sorted_series)
236+
237+
index_sorted_series = series.sort_index(kind="heapsort", key=sort_by_key)
238+
tm.assert_series_equal(expected_series, index_sorted_series)
239+
240+
def test_sort_index_kind_neg_key(self):
241+
# GH #14444 & #13589: Add support for sort algo choosing
242+
series = Series(index=[3, 2, 1, 4, 3], dtype=object)
243+
expected_series = Series(index=[4, 3, 3, 2, 1], dtype=object)
244+
245+
index_sorted_series = series.sort_index(kind="mergesort", key=lambda x: -x)
246+
tm.assert_series_equal(expected_series, index_sorted_series)
247+
248+
index_sorted_series = series.sort_index(kind="quicksort", key=lambda x: -x)
249+
tm.assert_series_equal(expected_series, index_sorted_series)
250+
251+
index_sorted_series = series.sort_index(kind="heapsort", key=lambda x: -x)
252+
tm.assert_series_equal(expected_series, index_sorted_series)
253+
254+
def test_sort_index_na_position_key(self, sort_by_key):
255+
series = Series(index=[3, 2, 1, 4, 3, np.nan], dtype=object)
256+
expected_series_first = Series(index=[np.nan, 1, 2, 3, 3, 4], dtype=object)
257+
258+
index_sorted_series = series.sort_index(na_position="first", key=sort_by_key)
259+
tm.assert_series_equal(expected_series_first, index_sorted_series)
260+
261+
expected_series_last = Series(index=[1, 2, 3, 3, 4, np.nan], dtype=object)
262+
263+
index_sorted_series = series.sort_index(na_position="last", key=sort_by_key)
264+
tm.assert_series_equal(expected_series_last, index_sorted_series)
265+
226266
def test_changes_length_raises(self):
227267
s = Series([1, 2, 3])
228268
with pytest.raises(ValueError, match="change the shape"):
229269
s.sort_index(key=lambda x: x[:1])
270+
271+
def test_sort_values_key_type(self):
272+
s = Series([1, 2, 3], DatetimeIndex(["2008-10-24", "2008-11-23", "2007-12-22"]))
273+
274+
result = s.sort_index(key=lambda x: x.month)
275+
expected = s.iloc[[0, 1, 2]]
276+
tm.assert_series_equal(result, expected)
277+
278+
result = s.sort_index(key=lambda x: x.day)
279+
expected = s.iloc[[2, 1, 0]]
280+
tm.assert_series_equal(result, expected)
281+
282+
result = s.sort_index(key=lambda x: x.year)
283+
expected = s.iloc[[2, 0, 1]]
284+
tm.assert_series_equal(result, expected)
285+
286+
result = s.sort_index(key=lambda x: x.month_name())
287+
expected = s.iloc[[2, 1, 0]]
288+
tm.assert_series_equal(result, expected)

pandas/tests/series/methods/test_sort_values.py

-45
Original file line numberDiff line numberDiff line change
@@ -209,48 +209,3 @@ def test_sort_values_key_nan(self):
209209
result = series.sort_values(0, key=lambda x: -x, ascending=False)
210210
expected = series.iloc[[0, 4, 3, 1, 2, 5]]
211211
tm.assert_series_equal(result, expected)
212-
213-
def test_sort_index_kind_key(self, sort_by_key):
214-
# GH #14444 & #13589: Add support for sort algo choosing
215-
series = Series(index=[3, 2, 1, 4, 3], dtype=object)
216-
expected_series = Series(index=[1, 2, 3, 3, 4], dtype=object)
217-
218-
index_sorted_series = series.sort_index(kind="mergesort", key=sort_by_key)
219-
tm.assert_series_equal(expected_series, index_sorted_series)
220-
221-
index_sorted_series = series.sort_index(kind="quicksort", key=sort_by_key)
222-
tm.assert_series_equal(expected_series, index_sorted_series)
223-
224-
index_sorted_series = series.sort_index(kind="heapsort", key=sort_by_key)
225-
tm.assert_series_equal(expected_series, index_sorted_series)
226-
227-
def test_sort_index_kind_neg_key(self):
228-
# GH #14444 & #13589: Add support for sort algo choosing
229-
series = Series(index=[3, 2, 1, 4, 3], dtype=object)
230-
expected_series = Series(index=[4, 3, 3, 2, 1], dtype=object)
231-
232-
index_sorted_series = series.sort_index(kind="mergesort", key=lambda x: -x)
233-
tm.assert_series_equal(expected_series, index_sorted_series)
234-
235-
index_sorted_series = series.sort_index(kind="quicksort", key=lambda x: -x)
236-
tm.assert_series_equal(expected_series, index_sorted_series)
237-
238-
index_sorted_series = series.sort_index(kind="heapsort", key=lambda x: -x)
239-
tm.assert_series_equal(expected_series, index_sorted_series)
240-
241-
def test_sort_index_na_position_key(self, sort_by_key):
242-
series = Series(index=[3, 2, 1, 4, 3, np.nan], dtype=object)
243-
expected_series_first = Series(index=[np.nan, 1, 2, 3, 3, 4], dtype=object)
244-
245-
index_sorted_series = series.sort_index(na_position="first", key=sort_by_key)
246-
tm.assert_series_equal(expected_series_first, index_sorted_series)
247-
248-
expected_series_last = Series(index=[1, 2, 3, 3, 4, np.nan], dtype=object)
249-
250-
index_sorted_series = series.sort_index(na_position="last", key=sort_by_key)
251-
tm.assert_series_equal(expected_series_last, index_sorted_series)
252-
253-
def test_changes_length_raises(self):
254-
s = Series([1, 2, 3])
255-
with pytest.raises(ValueError, match="change the shape"):
256-
s.sort_values(key=lambda x: x[:1])

0 commit comments

Comments
 (0)