Sorting and Top N
What You Will Learn in This Lesson
By the end of this lesson, you will be able to:
- Sort a table by one column, and by several.
- Say what
sort_valuesreturns. - Take the top few rows with
nlargest. - Decide what happens to ties and to missing values.
Why This Matters
Sorting is where the "returns a new table" rule bites hardest, because a sort you forget to assign looks like a sort that did not work. And "the top five" is a question worth asking directly rather than by sorting everything and slicing.
Step 1: sort_values returns a new table
by names the column, ascending chooses the direction, and the original is untouched unless you reassign.
The result is the point
Same rule as drop and rename. Calling it and ignoring the return is a no-op.
import pandas as pd
df = pd.DataFrame({"name": ["Ada", "Alan"], "score": [92, 79]})
df.sort_values("score")
print(df) # unchanged
print(df.sort_values("score"))
Several columns, and ties
A list of columns sorts by the first, then breaks ties with the second. Without a tiebreaker the order among equal values is whatever it was — stable, but not meaningful.
import pandas as pd
df = pd.DataFrame({"city": ["Y", "L", "L"], "name": ["Bo", "Zoe", "Ada"], "score": [88, 88, 92]})
print(df.sort_values(["score", "name"], ascending=[False, True]))
Where missing values go
NaN sorts to the end by default, whichever direction you chose. na_position="first" changes it — and if the missing rows matter, saying so beats letting them sit quietly at the bottom.
import pandas as pd
import numpy as np
df = pd.DataFrame({"score": [92, np.nan, 79]})
print(df.sort_values("score")["score"].tolist())
print(df.sort_values("score", na_position="first")["score"].tolist())
Mini Practice #1: The sort that did nothing
Try It YourselfRun this as it stands, then fix it so the table actually comes back sorted.
Step 2: nlargest says what you meant
Sorting the whole table to look at three rows is more work than the question needs, and reads less clearly.
The top few, directly
It takes the count and the column, and does both the ordering and the slice. Asking for more rows than exist gives you all of them rather than an error.
import pandas as pd
df = pd.DataFrame({"name": ["Ada", "Grace", "Alan"], "score": [92, 88, 79]})
print(df.nlargest(2, "score"))
print(df.nlargest(10, "score").shape)
And the bottom few
nsmallest is the same idea the other way up, and is clearer than sorting ascending and taking the head.
import pandas as pd
df = pd.DataFrame({"name": ["Ada", "Grace", "Alan"], "score": [92, 88, 79]})
print(df.nsmallest(1, "score")["name"].tolist())
Mini Practice #2: Top three, two ways
Try It YourselfTake the three highest scores by sorting and slicing, and then with nlargest. Check they agree.
Step 3: When to Use It
Ranking a table
sort_values by one or more columns, with a direction for each.
df.sort_values(["score", "name"], ascending=[False, True])
The few rows that matter
nlargest and nsmallest take the top or bottom n directly.
When Not to Use It
Do not rely on head() after a sort you did not assign. sort_values returns a new table; the original keeps its old order.
End-of-Lesson Exercises
Exercise 1: The top scorers
Write top_names(df, n) returning the names of the n highest scorers, best first.
nlargest takes the count and the column and does both the sort and the slice. Sorting ascending and taking the head gives you the worst, not the best.
Exercise 2: Break the tie on purpose
Write ranked(df) returning every name ordered by score highest first, with ties broken by name alphabetically. Without the tiebreaker the order among equal scores is not meaningful.
sort_values takes a list of columns and a matching list of directions: ["score", "name"] with ascending=[False, True].