Sorting: sort_values, sort_index, nlargest
Order rows by one or many columns with sort_values (ascending lists, na_position, ignore_index), by labels with sort_index, and grab top-N rows with nlargest / nsmallest.
"Orange Cap leaderboard — highest runs first." "Sort by team, and inside each team by runs." "Top 3 wicket-takers." Sorting turns a table into an answer. Pandas sorts by values (sort_values), by labels (sort_index), and has shortcuts for top/bottom-N (nlargest, nsmallest).
Definition
DataFrame.sort_values(by)returns a new DataFrame with rows reordered by the values of one or more columns.DataFrame.sort_index()reorders rows (or columns) by their labels.nlargest(n, columns)/nsmallest(n, columns)return the n rows with the largest / smallest values directly.
- Reordered — rows move together with their index labels; nothing inside a row changes. After sorting, labels look jumbled (0, 6, 1…) — that's expected.
- One or more columns — with several columns, the first is the main sort key, the next breaks ties, and so on (like sorting a points table by points, then net run rate).
- New DataFrame — the original order is untouched unless you reassign.
Syntax
python
df.sort_values(by, ascending=True, na_position="last", ignore_index=False, key=None)
df.sort_index(axis=0, ascending=True)
df.nlargest(n, columns, keep="first")
df.nsmallest(n, columns, keep="first")| Parameter | Meaning | Default |
|---|---|---|
by | column name, or list of names (priority order) | required |
ascending | True = small→large / A→Z; a list gives one direction per column | True |
na_position | where NaNs go: "last" or "first" | "last" |
ignore_index | renumber the result 0…n-1 | False |
key | function applied to the column before sorting (e.g. lambda s: s.str.lower()) | None |
axis (sort_index) | 0 sort rows by index labels, 1 sort columns by name | 0 |
n, columns (nlargest) | how many rows, and which column(s) to rank by | required |
keep (nlargest) | ties at the cut-off: "first", "last" or "all" | "first" |
Example — sort by one column
python
print(players.sort_values("runs"))
print(players.sort_values("runs", ascending=False)[["player", "runs"]])text
player team role runs wickets strike_rate
3 Jasprit Bumrah MI Bowler 8 20 80.0
7 Rashid Khan GT Bowler 102 10 120.0
2 MS Dhoni CSK Keeper 161 0 220.5
4 Hardik Pandya MI All-rounder 216 11 143.0
5 Ravindra Jadeja CSK All-rounder 267 8 157.1
1 Rohit Sharma MI Batter 417 0 150.0
6 Shubman Gill GT Batter 426 0 147.4
0 Virat Kohli RCB Batter 741 0 154.7
player runs
0 Virat Kohli 741
6 Shubman Gill 426
1 Rohit Sharma 417
5 Ravindra Jadeja 267
4 Hardik Pandya 216
2 MS Dhoni 161
7 Rashid Khan 102
3 Jasprit Bumrah 8How it works: the default is ascending (smallest first). ascending=False gives the leaderboard order. Each row kept its original label — Kohli is still label 0 — which is why the index on the left looks shuffled.
Example — sort by several columns
python
print(players.sort_values(["team", "runs"], ascending=[True, False])[["player", "team", "runs"]])text
player team runs
5 Ravindra Jadeja CSK 267
2 MS Dhoni CSK 161
6 Shubman Gill GT 426
7 Rashid Khan GT 102
1 Rohit Sharma MI 417
4 Hardik Pandya MI 216
3 Jasprit Bumrah MI 8
0 Virat Kohli RCB 741How it works: rows are first ordered by team A→Z (CSK, GT, MI, RCB). Within each team, they're ordered by runs — and because ascending=[True, False], the second key is descending, so each team's top scorer comes first. The ascending list must have one entry per column in by.
Example — missing values, ignore_index and sort_index
python
import numpy as np
d = pd.DataFrame({"player": ["A", "B", "C", "D"], "runs": [50, np.nan, 20, 80]})
print(d.sort_values("runs"))
print(d.sort_values("runs", na_position="first"))
print(players.sort_values("runs", ascending=False, ignore_index=True)[["player", "runs"]].head(3))
s = players.sort_values("runs", ascending=False)
print(s.sort_index()[["player", "runs"]].head(3))text
player runs
2 C 20.0
0 A 50.0
3 D 80.0
1 B NaN
player runs
1 B NaN
2 C 20.0
0 A 50.0
3 D 80.0
player runs
0 Virat Kohli 741
1 Shubman Gill 426
2 Rohit Sharma 417
player runs
0 Virat Kohli 741
1 Rohit Sharma 417
2 MS Dhoni 161How it works: NaN always goes to the end by default — whether ascending or descending; na_position="first" moves it to the top. ignore_index=True sorts and renumbers in one step (same as adding .reset_index(drop=True)). sort_index() sorts by the labels, so it restores the original order of a sorted table. On a named index (set_index("player")) it sorts alphabetically by name, and sort_index(axis=1) sorts the columns by name.
Example — nlargest and nsmallest
python
print(players.nlargest(3, "runs")[["player", "runs"]])
print(players.nsmallest(2, "strike_rate")[["player", "strike_rate"]])
print(players.nsmallest(3, "wickets")[["player", "wickets"]])
print(players.nsmallest(3, "wickets", keep="all")[["player", "wickets"]])text
player runs
0 Virat Kohli 741
6 Shubman Gill 426
1 Rohit Sharma 417
player strike_rate
3 Jasprit Bumrah 80.0
7 Rashid Khan 120.0
player wickets
0 Virat Kohli 0
1 Rohit Sharma 0
2 MS Dhoni 0
player wickets
0 Virat Kohli 0
1 Rohit Sharma 0
2 MS Dhoni 0
6 Shubman Gill 0How it works: nlargest(3, "runs") = sort_values("runs", ascending=False).head(3), but clearer and faster on big data (it doesn't sort everything). Ties: four players have 0 wickets. With the default keep="first", only the first 3 are returned; keep="all" keeps every tied row, so you get 4. nlargest works only on numeric columns — for text, use sort_values.
Comparison — which sorting tool?
| Want | Use |
|---|---|
| Whole table ordered by a column | sort_values("runs", ascending=False) |
| Order by several columns, mixed directions | sort_values(["team", "runs"], ascending=[True, False]) |
| Just the top / bottom N by a number | nlargest(n, "col") / nsmallest(n, "col") |
| Back to original row order, or alphabetical by index | sort_index() |
| Columns in alphabetical order | sort_index(axis=1) |
| A single column's values sorted | df["runs"].sort_values() (a Series) |
Common mistakes
- ❌
players.sort_values("runs")and then printingplayers— unchanged! ✅ Reassign:players = players.sort_values("runs"). (sort_values(..., inplace=True)returnsNoneand is discouraged.) - ❌
sort_values(["team", "runs"], ascending=False)when only runs should be descending. ✅ascending=[True, False]. - ❌
sort_values(by="Runs")→KeyError: 'Runs'. ✅ Exact, case-sensitive column name. - ❌ Using
loc[0:3]to take the top 3 after sorting. ✅ Labels moved with the rows — usehead(3),iloc[0:3]ornlargest(3, ...). - ❌ Expecting
keep="first"innlargestto show all tied players. ✅ Usekeep="all".
Interview tip
Q: How do you sort a DataFrame by team ascending and runs descending?
A: df.sort_values(["team", "runs"], ascending=[True, False]). The by list sets the priority (team first, runs breaks ties within a team), and the ascending list gives each column its own direction.
Key points to remember
- sort_values('col') orders rows by a column — ascending by default; ascending=False for descending.
- Sort by several columns with a list; ascending=[True, False] sets a direction per column.
- Rows keep their index labels when sorted; ignore_index=True (or reset_index(drop=True)) renumbers them.
- NaN goes last by default; na_position='first' puts missing values on top.
- sort_index() sorts by row labels (restores original order); sort_index(axis=1) sorts columns by name.
- nlargest(n, col) / nsmallest(n, col) return top/bottom N rows; keep='all' keeps ties.
- Sorting returns a new DataFrame — reassign it to keep the order.
Try it yourself
Leaderboard with sort_values
Missing values and sort_index
nlargest, nsmallest and ties
Practice: MI players sorted by runs
Revision Flashcards
Tap a card to flip it and see the answer.
