Sorting and Ranking
Reviewed & published by Brayan K
Sorting in pandas is the process of reordering the rows of a DataFrame or Series so the values follow a chosen order, while ranking assigns each value a position number relative to the others.
Part of the free Pandas course at LearnCodingFast — hands-on lessons with examples you run in your browser, plus practice exercises and a quick quiz.
Learn how to order data by one or many columns, control where missing values land, sort by the index, and turn values into competition-style rankings.
What You'll Learn in This Lesson
- Sort a DataFrame by a single column with sort_values
- Reverse order with ascending=False
- Sort by multiple columns using by=[...]
- Control where NaN lands with na_position
- Reorder by index labels with sort_index
- Rank values with method='min' and 'dense'
1 Sorting by a Column with sort_values()
The workhorse for ordering data is df.sort_values("column"). It returns a new DataFrame with the rows rearranged so the chosen column is in ascending order by default. The index travels with each row, so you can always see where a row originally came from.
import pandas as pd
df = pd.DataFrame({
"name": ["Ava", "Ben", "Cara", "Dan"],
"age": [34, 22, 29, 41],
"city": ["Leeds", "York", "Leeds", "Hull"],
})
# Sort rows so age goes from smallest to largest
by_age = df.sort_values("age")
print(by_age)
# Row order becomes Ben (22), Cara (29), Ava (34), Dan (41)
# Sort largest to smallest with ascending=False
oldest_first = df.sort_values("age", ascending=False)
print(oldest_first)
# Row order becomes Dan (41), Ava (34), Cara (29), Ben (22)
# ✅ Expected output:
# name age city
# 1 Ben 22 York
# 2 Cara 29 Leeds
# 0 Ava 34 Leeds
# 3 Dan 41 Hull
# name age city
# 3 Dan 41 Hull
# 0 Ava 34 Leeds
# 2 Cara 29 Leeds
# 1 Ben 22 York2 Sorting by Multiple Columns and Placing NaN
Pass a list to by=["a", "b"] to sort by several columns at once. Pandas sorts by the first column, then breaks ties using the second, and so on. You can give each column its own direction by passing a list of booleans to ascending.
Missing values (NaN) are handled by the na_position argument, which defaults to "last". Set it to "first" to push missing rows to the top instead.
import pandas as pd
import numpy as np
df = pd.DataFrame({
"city": ["Leeds", "Leeds", "York", "York", "Hull"],
"age": [34, 29, 22, np.nan, 41],
"name": ["Ava", "Cara", "Ben", "Eve", "Dan"],
})
# Sort by city A-Z, then within each city by age high-to-low
result = df.sort_values(by=["city", "age"], ascending=[True, False])
print(result)
# Put rows with a missing age at the TOP instead of the bottom
nan_first = df.sort_values("age", na_position="first")
print(nan_first)
# Eve (NaN age) now appears as the first row
# ✅ Expected output:
# city age name
# 4 Hull 41.0 Dan
# 0 Leeds 34.0 Ava
# 1 Leeds 29.0 Cara
# 2 York 22.0 Ben
# 3 York NaN Eve
# city age name
# 3 York NaN Eve
# 2 York 22.0 Ben
# 1 Leeds 29.0 Cara
# 0 Leeds 34.0 Ava
# 4 Hull 41.0 Dan3 Sorting by Index and Tidying With reset_index()
Sometimes you want to order by the index labels rather than the data. That is what df.sort_index() does. After a value sort the index often looks jumbled, so calling reset_index(drop=True) renumbers the rows 0, 1, 2, ... for a clean look.
import pandas as pd
df = pd.DataFrame(
{"score": [88, 71, 95]},
index=["c", "a", "b"],
)
# Order rows by their index labels a, b, c
print(df.sort_index())
# score
# a 71
# b 95
# c 88
# After a value sort, the index is out of order
ranked = df.sort_values("score", ascending=False)
print(ranked.index.tolist()) # ['b', 'c', 'a']
# Renumber the rows 0,1,2 and drop the old index
tidy = ranked.reset_index(drop=True)
print(tidy)
# ✅ Expected output:
# score
# a 71
# b 95
# c 88
# ['b', 'c', 'a']
# score
# 0 95
# 1 88
# 2 714 Ranking Values With rank()
Series.rank() assigns each value its position relative to the others. The method argument decides how ties are handled. method="min" gives tied values the lowest available rank and leaves a gap afterwards. method="dense" also gives ties the same rank but never skips numbers, so ranks step up by exactly 1.
import pandas as pd
scores = pd.Series([90, 90, 80, 70], index=["a", "b", "c", "d"])
# method='min': tied 90s both get rank 1, then a gap to 3
print(scores.rank(method="min", ascending=False))
# a -> 1.0, b -> 1.0, c -> 3.0, d -> 4.0
# method='dense': tied 90s get rank 1, no gap, next is 2
print(scores.rank(method="dense", ascending=False))
# a -> 1.0, b -> 1.0, c -> 2.0, d -> 3.0
# ✅ Expected output:
# a 1.0
# b 1.0
# c 3.0
# d 4.0
# dtype: float64
# a 1.0
# b 1.0
# c 2.0
# d 3.0
# dtype: float64🎯 Your Turn: Top Sellers
Replace the blank so the products are sorted by sales from highest to lowest. The first printed row should be the "Laptop" with 920 sales.
import pandas as pd
df = pd.DataFrame({
"product": ["Mouse", "Laptop", "Keyboard", "Monitor"],
"sales": [310, 920, 540, 480],
})
# 🎯 YOUR TURN: sort by 'sales' with the biggest first
top = df.sort_values("sales", ascending=___)
print(top)
# Expected first row: Laptop with 920 sales,
# then Keyboard 540, Monitor 480, Mouse 310📋 Quick Reference
| Task | Code |
|---|---|
| Sort by one column | df.sort_values("col") |
| Descending | df.sort_values("col", ascending=False) |
| Multiple columns | df.sort_values(by=["a", "b"]) |
| NaN at the top | df.sort_values("col", na_position="first") |
| Sort by index | df.sort_index() |
| Renumber rows | df.reset_index(drop=True) |
| Rank a Series | s.rank(method="dense") |
🎯 Mini Challenge: Class Leaderboard
Build a leaderboard: sort students by score (high to low), add a dense rank column, and renumber the rows.
import pandas as pd
df = pd.DataFrame({
"student": ["Ivy", "Jon", "Kim", "Leo"],
"score": [88, 95, 88, 73],
})
# 1. Add a competition rank (highest score = rank 1, dense ties)
df["rank"] = df["score"].rank(method="dense", ascending=False).astype(int)
# 2. Sort by score high-to-low, then reset the index
board = df.sort_values("score", ascending=False).reset_index(drop=True)
print(board)
# Jon 95 -> rank 1, Ivy 88 -> rank 2, Kim 88 -> rank 2, Leo 73 -> rank 3
# ✅ Expected output:
# student score rank
# 0 Jon 95 1
# 1 Ivy 88 2
# 2 Kim 88 2
# 3 Leo 73 3❓ Frequently Asked Questions
Lesson complete — you can order any dataset!
You can now sort by one or many columns, flip the direction, decide where missing values go, sort by the index, and turn values into rankings. These are the building blocks for every report and leaderboard you will ever make.
Practice quiz
Which method sorts a DataFrame by the data in a column?
- df.sort_values('col')
- df.order('col')
- df.arrange('col')
- df.sortby('col')
Answer: df.sort_values('col'). sort_values('col') orders rows by that column's values.
What is the default sort direction of sort_values()?
- Descending
- Ascending
- Random
- By index
Answer: Ascending. By default ascending=True, so values sort smallest to largest.
How do you sort from largest to smallest?
- sort_values('v', reverse=True)
- sort_values('v', desc=True)
- sort_values('v', ascending=False)
- sort_values('v', order='down')
Answer: sort_values('v', ascending=False). Pass ascending=False to sort in descending order.
Which method sorts by the row labels instead of values?
- df.sort_labels()
- df.sort_keys()
- df.reindex()
- df.sort_index()
Answer: df.sort_index(). sort_index() orders rows by their index labels.
How do you sort by column 'a' then break ties with 'b'?
- df.sort_values(['a', 'b'])
- df.sort_values('a', 'b')
- df.sort_values('a').sort('b')
- df.sort_values({'a','b'})
Answer: df.sort_values(['a', 'b']). Pass a list; pandas sorts by 'a' first, then 'b' within ties.
What does sort_values() return by default?
- None
- A new sorted DataFrame, leaving the original unchanged
- Only the sorted column
- A boolean
Answer: A new sorted DataFrame, leaving the original unchanged. It returns a new frame; use inplace=True to modify the original.
Where do NaN values go by default in sort_values()?
- First
- They raise an error
- At the end (last)
- They are dropped
Answer: At the end (last). na_position defaults to 'last', placing NaN at the end.
Which method returns the 3 largest values of a Series directly?
- s.top(3)
- s.maxn(3)
- s.biggest(3)
- s.nlargest(3)
Answer: s.nlargest(3). nlargest(3) returns the three biggest values, already sorted.
How do you put NaN values first when sorting?
- sort_values(na_position='first')
- sort_values(nan='top')
- sort_values(na='start')
- sort_values(missing='first')
Answer: sort_values(na_position='first'). na_position='first' moves NaN values to the top.
Does sort_values() change the original DataFrame's order in place by default?
- No, it returns a sorted copy
- Yes, always in place
- Only for numeric columns
- Only if there are ties
Answer: No, it returns a sorted copy. Without inplace=True it leaves the original untouched and returns a copy.
Continue this course
- Previous: Handling Missing Data (NaN, fillna, dropna)
- Next: idxmax & idxmin: Find the Row Behind the Max — Get the whole record holding the largest value, not just the number
- Quick reference: Pandas cheat sheet › Transforming
Frequently asked questions
What is the difference between sort_values and sort_index in pandas?
sort_values() reorders rows based on the data inside one or more columns, while sort_index() reorders rows based on the index labels. Use sort_values to rank by a value like price, and sort_index to restore the original or alphabetical index order.
How do I sort a pandas DataFrame in descending order?
Pass ascending=False to sort_values, for example df.sort_values('price', ascending=False). When sorting by multiple columns you can pass a list of booleans, like ascending=[True, False], to control each column independently.
What does rank(method='dense') do in pandas?
rank() assigns a numeric rank to each value. method='min' gives tied values the lowest rank and leaves gaps, while method='dense' also gives ties the same rank but never leaves gaps, so ranks increase by exactly 1 each step.