Sorting is one of the most fundamental operations in data analysis. Whether you are ranking transactions by value, ordering time series, or simply inspecting the largest and smallest records, you need a reliable way to reorder rows.
If you have used pandas, you are familiar with sort_values(), ascending=False, and na_position. Polars takes a cleaner approach: a single .sort() method with intuitive parameters like descending and nulls_last. It also provides top_k() and bottom_k() to efficiently retrieve the largest or smallest rows without sorting the entire DataFrame.
This article covers seven patterns, each demonstrated on an interactive dataset you can edit and run directly in your browser:
- Create the fuel dataset
.sort('col')— basic ascending sort.sort('col', descending=True)— descending sort.sort('col', nulls_last=False)— control null positioning.sort(['col1', 'col2'])— multi-column sort.top_k(n, by='col')— top k values.bottom_k(n, by='col')— bottom k values
The dataset
We will use a small petrol station dataset. Each row represents a fuel transaction recorded at stations across Australia. The columns capture the station name, fuel type, litres sold, price per litre, and the state where the station is located. Some values are intentionally missing (null) to demonstrate how sorting handles gaps in data.
The dataset has 15 transactions spread across three Australian petrol stations: Caltex Bondi (NSW), BP Southbank (VIC) and Shell Fortitude Valley (QLD). Notice that two litres values and one state value are null — these will help us explore how Polars handles missing data during sorting.
Basic ascending sort
The simplest sort orders rows from smallest to largest. Pass the column name to .sort():
Polars sorts in ascending order by default. The two rows with null litres values are placed at the bottom — Polars treats null as the largest possible value by default (i.e. nulls_last=True).
Descending sort
To sort from largest to smallest, set descending=True:
This is the Polars equivalent of pandas sort_values('litres', ascending=False). The parameter name is more intuitive — descending=True reads naturally as "sort in descending order".
Controlling null positioning
By default, Polars places null values at the end of a sorted result. To move them to the top, set nulls_last=False:
This is the Polars equivalent of pandas na_position='first'. Placing nulls first is useful when you want to quickly inspect which rows are missing data before analysing the rest.
Multi-column sort
Pass a list of column names to sort by multiple columns. You can control the direction of each column independently by passing a list to descending:
The first column (state) is sorted in ascending alphabetical order. Within each state, rows are then sorted by litres in descending order. This is equivalent to pandas sort_values(['state', 'litres'], ascending=[True, False]) — but with clearer parameter naming.
Top k values
When you only need the largest rows, top_k() is more efficient than sorting the entire DataFrame and slicing:
top_k() returns the n rows with the largest values in the specified column, sorted from largest to smallest. This is the Polars equivalent of pandas nlargest(5, 'litres'). Under the hood, Polars uses a partial sort, which is faster than a full sort when n is much smaller than the total number of rows.
Bottom k values
The counterpart to top_k() is bottom_k(), which returns the smallest rows:
bottom_k() returns the n rows with the smallest values, sorted from smallest to largest. This is the Polars equivalent of pandas nsmallest(5, 'litres'). Together with top_k(), these methods let you quickly inspect the extremes of your data without sorting every row.
Polars vs pandas: sorting compared
If you are coming from pandas, here is how the key sorting operations map:
df.sort_values('col')→df.sort('col')ascending=False→descending=Truena_position='first'→nulls_last=Falsedf.nlargest(5, 'col')→df.top_k(5, by='col')df.nsmallest(5, 'col')→df.bottom_k(5, by='col')
The core advantage: Polars uses clearer parameter names (descending instead of ascending, nulls_last instead of na_position) and provides dedicated top_k/bottom_k methods that are both more readable and more efficient than sorting and slicing.
Try editing the code blocks above — sort by price per litre instead of litres, change the number of rows in top_k, or combine descending=True with nulls_last=False to see how the parameters interact.
References
- Polars documentation: polars.DataFrame.sort
- Polars documentation: polars.DataFrame.top_k
- Polars documentation: polars.DataFrame.bottom_k
- Polars user guide: Sorting
- Related: How to Group Data with Polars