Sorting and ranking

pandas · Essentials · 8 min

Sorted output is how people read results, and top-n queries appear in almost every report.

`df.sort_values(by)` sorts rows by one or more columns and returns a new DataFrame. Pass a list for multiple keys and a matching list for direction:

df.sort_values(["country", "sales"], ascending=[True, False])

Missing values go last by default; na_position="first" changes that. The original index labels travel with their rows, so after sorting, df.loc[0] is still the same row it was before, and df.iloc[0] is the new first row. Add ignore_index=True to renumber.

For a single column, the default algorithm is quicksort, which isn't stable; pass kind="stable" if equal values must keep their existing order. Sorting by several columns is always stable.

`df.sort_index()` sorts by the row labels instead, which matters for time series and for fast label slicing. axis=1 sorts the columns by name.

For "top n" questions, `df.nlargest(5, "sales")` and nsmallest are clearer and faster than sorting everything and taking head.

`rank()` assigns positions to values: df["sales"].rank(ascending=False) gives 1 to the biggest. The method= argument decides how ties are treated: "average" (default), "min" (like sports rankings: 1, 2, 2, 4), "dense" (1, 2, 2, 3) or "first".

Sorting by a computed value doesn't need a temporary column: key= takes a function applied to the column before comparing, e.g. df.sort_values("name", key=lambda s: s.str.lower()) for case-insensitive order.

Example

import pandas as pd

df = pd.DataFrame({
    "rep": ["ana", "Bo", "cy", "Di", "ed"],
    "region": ["N", "S", "N", "S", "N"],
    "sales": [120, 340, 340, 90, None],
})
print(df.sort_values("sales", ascending=False).rep.tolist())
# ['Bo', 'cy', 'ana', 'Di', 'ed']   NaN last

print(df.sort_values(["region", "sales"], ascending=[True, False]).rep.tolist())
# ['cy', 'ana', 'ed', 'Bo', 'Di']

print(df.nlargest(2, "sales").rep.tolist())        # ['Bo', 'cy']
print(df["sales"].rank(ascending=False, method="min").tolist())
# [3.0, 1.0, 1.0, 4.0, nan]

print(df.sort_values("rep", key=lambda s: s.str.lower()).rep.tolist())
# ['ana', 'Bo', 'cy', 'Di', 'ed']

Remember

  • sort_values(by, ascending=...) accepts lists of keys and directions
  • Index labels move with rows; use ignore_index=True to renumber
  • nlargest/nsmallest answer top-n questions directly
  • rank(method=...) controls how ties are numbered

Watch out for

  • Calling df.sort_values('x') without assigning the result and wondering why df is unchanged.

Check yourself

  1. Values [50, 80, 80, 30] ranked with `rank(ascending=False, method='dense')` give?

Sign in to answer, see the explanations, and get this lesson back as a quick review later.

Official docs: pandas.pydata.org/docs/reference/api/pandas.DataFrame.sort_values.html