Sorting and Ranking
Sorting rearranges rows so that a chosen column (or the index) is in ascending or descending order, while ranking assigns each value a numeric position relative to the others without necessarily reordering the data itself. Pandas exposes sort_values and sort_index for the former, and rank for the latter. These operations are foundational: leaderboard tables, top-N reports, percentile calculations, and time-ordered analysis all depend on getting sorting and ranking semantics right — especially around how ties and missing values are handled.
Cricket analogy: Sorting rearranges a season's scorecard so Virat Kohli's highest score sits at the top, while ranking assigns him a position (like 3rd-highest run-scorer) without reordering the underlying match list, which matters for building an accurate leaderboard.
sort_values: ordering by column content
DataFrame.sort_values(by=...) reorders rows based on the values in one or more columns. Passing a list to by sorts hierarchically — the first column breaks the biggest ties, subsequent columns break ties within those. The ascending parameter can be a single bool or a list matching the by list, letting you mix ascending and descending order across columns in a single call. By default, NaN values are pushed to the end of the sort regardless of direction, which is controlled by the na_position parameter ('last' by default, or 'first').
Cricket analogy: sort_values(by=['team','runs'], ascending=[True, False]) groups a scorecard by team alphabetically first, then ranks each team's batters highest-runs-first within that group, and na_position='last' pushes any player missing a runs entry to the bottom regardless of sort direction.
import pandas as pd
import numpy as np
students = pd.DataFrame({
'name': ['Ravi', 'Meera', 'Anil', 'Divya', 'Kiran'],
'grade': [9, 10, 9, 8, np.nan],
'score': [88, 95, 91, 76, 60]
})
# Sort by grade descending, then score descending within each grade
ranked = students.sort_values(by=['grade', 'score'], ascending=[False, False], na_position='last')
print(ranked)
# name grade score
# 1 Meera 10.0 95
# 2 Anil 9.0 91
# 0 Ravi 9.0 88
# 3 Divya 8.0 76
# 4 Kiran NaN 60sort_index: ordering by the index
sort_index reorders rows (or columns, with axis=1) by the index labels rather than by cell values. This is especially useful after operations like groupby or merge that can leave the index in a non-obvious order, or after filtering that leaves gaps in a RangeIndex. For a MultiIndex, sort_index accepts a level argument to sort by a specific index level, and can sort remaining levels lexicographically by default.
Cricket analogy: sort_index() after a groupby that produced runs-per-team leaves teams out of alphabetical order; calling sort_index() restores it, and for a MultiIndex of team-then-player, passing level='team' sorts only by team while player order within remains lexicographic.
rank: assigning positions and handling ties
Series.rank() (and DataFrame.rank() applied per column) returns a same-shaped object where each value is replaced by its rank among the other values, with 1 being the lowest by default. The method parameter controls tie-breaking: 'average' (default) gives tied values the mean of the ranks they would occupy; 'min' gives all tied values the lowest of those ranks; 'max' gives the highest; 'first' breaks ties by order of appearance; and 'dense' behaves like 'min' but doesn't leave gaps in the rank sequence. Choosing the right method matters for leaderboards (where 'min' avoids skipping a rank after a tie) versus dense classification schemes.
Cricket analogy: Series.rank() on a season's run totals with method='min' means two batters tied for 2nd both get rank 2, avoiding a skipped rank 3, which matters for an accurate Orange Cap leaderboard, while 'dense' would rank the next distinct total as 3 without a gap.
import pandas as pd
scores = pd.Series([88, 95, 88, 76], index=['Ravi', 'Meera', 'Anil', 'Divya'])
print(scores.rank(ascending=False, method='min'))
# Meera 1.0
# Ravi 2.0
# Anil 2.0
# Divya 4.0 <- 'min' skips rank 3 because two values tied for 2
print(scores.rank(ascending=False, method='dense'))
# Meera 1.0
# Ravi 2.0
# Anil 2.0
# Divya 3.0 <- 'dense' does not skip a rank numberrank(pct=True) converts ranks into percentiles between 0 and 1, which is a quick way to compute percentile scores for a column without manually dividing by the count.
sort_values does not sort in place by default — it returns a new DataFrame. Forgetting to reassign (df = df.sort_values(...)) or pass inplace=True is a very common bug that leaves the original order untouched.
- sort_values orders rows by one or more column values; sort_index orders by the index labels.
- Passing a list to by/ascending in sort_values enables multi-column, mixed-direction sorting.
- NaN values sort to the end by default in sort_values, controllable via na_position.
- rank() assigns numeric positions to values, with tie-breaking controlled by the method parameter.
- method='min' vs 'dense' differ in whether tied ranks leave gaps in the subsequent rank numbers.
- sort_values and sort_index return new objects by default; use inplace=True or reassignment to persist the change.
Practice what you learned
1. What does `df.sort_values(by=['dept', 'salary'], ascending=[True, False])` do?
2. By default, where do NaN values end up after calling sort_values on a column containing them?
3. Given the values [10, 20, 20, 30] ranked ascending, what ranks does method='min' assign?
4. What distinguishes rank(method='dense') from rank(method='min')?
5. Which method call would sort a DataFrame by its row labels rather than by any column's values?
Was this page helpful?
You May Also Like
DataFrame Basics
Understand the structure of a pandas DataFrame — rows, columns, index, and dtypes — and the core operations for creating, inspecting, and selecting from tabular data.
Aggregation Functions
Explore the built-in and custom aggregation functions available after groupby, including agg() for applying multiple statistics at once.
GroupBy Basics
Understand pandas' split-apply-combine model via groupby(), including grouping keys, selecting columns, and iterating over groups.
Binning and Discretization
Turning continuous numeric data into discrete categorical buckets using pandas' cut and qcut functions, and why bin edges and labels matter for downstream analysis.