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

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   York

2 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   Dan

3 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     71

4 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

TaskCode
Sort by one columndf.sort_values("col")
Descendingdf.sort_values("col", ascending=False)
Multiple columnsdf.sort_values(by=["a", "b"])
NaN at the topdf.sort_values("col", na_position="first")
Sort by indexdf.sort_index()
Renumber rowsdf.reset_index(drop=True)
Rank a Seriess.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

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.