Sorting a DataFrame by its structural labels - row index and column names - is essential for organizing data consistently. The sort_index() method in Pandas handles both operations depending on which axis you specify.
This guide explains how to sort by row index, by column names, and by both simultaneously, with clear examples showing the before and after states.
Understanding sort_index() Syntax
DataFrame.sort_index(axis=0, ascending=True, inplace=False, kind='quicksort')| Parameter | Description | Default |
|---|---|---|
axis |
0 to sort rows by their index labels; 1 to sort columns by their names |
0 |
ascending |
True for ascending (A→Z, 0→9); False for descending |
True |
inplace |
If True, modifies the original DataFrame; if False, returns a new one |
False |
kind |
Sorting algorithm: 'quicksort', 'mergesort', 'heapsort' |
'quicksort' |
Sample DataFrame
All examples use this DataFrame where both the row index and column names are intentionally out of order:
import pandas as pd
df = pd.DataFrame(
{'col2': [150, 170, 160],
'col1': [70, 55, 60]},
index=[3, 2, 1]
)
print(df)Output:
col2 col1
3 150 70
2 170 55
1 160 60The row index is [3, 2, 1] (descending) and the columns are ['col2', 'col1'] (reverse alphabetical).
Sorting by Row Index
Setting axis=0 (or omitting the parameter since it's the default) sorts rows by their index labels:
import pandas as pd
df = pd.DataFrame(
{'col2': [150, 170, 160],
'col1': [70, 55, 60]},
index=[3, 2, 1]
)
sorted_by_index = df.sort_index(axis=0)
print(sorted_by_index)Output:
col2 col1
1 160 60
2 170 55
3 150 70Rows are now ordered by index: 1, 2, 3. The column order remains unchanged.
Descending Order
import pandas as pd
df = pd.DataFrame(
{'col2': [150, 170, 160],
'col1': [70, 55, 60]},
index=[3, 2, 1]
)
sorted_desc = df.sort_index(axis=0, ascending=False)
print(sorted_desc)Output:
col2 col1
3 150 70
2 170 55
1 160 60Sorting by Column Names
Setting axis=1 sorts the columns alphabetically by their names:
import pandas as pd
df = pd.DataFrame(
{'col2': [150, 170, 160],
'col1': [70, 55, 60]},
index=[3, 2, 1]
)
sorted_by_columns = df.sort_index(axis=1)
print(sorted_by_columns)Output:
col1 col2
3 70 150
2 55 170
1 60 160The columns are now in alphabetical order: col1, col2. The row order remains unchanged.
Sorting by Both Index and Column Names
To sort by both axes, chain two sort_index() calls - one for rows and one for columns:
import pandas as pd
df = pd.DataFrame(
{'col2': [150, 170, 160],
'col1': [70, 55, 60]},
index=[3, 2, 1]
)
print("Original DataFrame:")
print(df)
sorted_both = df.sort_index(axis=0).sort_index(axis=1)
print("\nSorted by both index and column names:")
print(sorted_both)Output:
Original DataFrame:
col2 col1
3 150 70
2 170 55
1 160 60
Sorted by both index and column names:
col1 col2
1 60 160
2 55 170
3 70 150Both the row index (1, 2, 3) and column names (col1, col2) are now in ascending alphabetical/numerical order.
Temporary vs. Permanent Sorting
By default, sort_index() returns a new DataFrame and leaves the original unchanged. Use inplace=True to modify the original directly.
Temporary Sort (Default)
import pandas as pd
df = pd.DataFrame(
{'col2': [150, 170, 160],
'col1': [70, 55, 60]},
index=[3, 2, 1]
)
result = df.sort_index(axis=1)
print("Result (sorted):")
print(result)
print("\nOriginal df (unchanged):")
print(df)Output:
Result (sorted):
col1 col2
3 70 150
2 55 170
1 60 160
Original df (unchanged):
col2 col1
3 150 70
2 170 55
1 160 60Permanent Sort with inplace=True
import pandas as pd
df = pd.DataFrame(
{'col2': [150, 170, 160],
'col1': [70, 55, 60]},
index=[3, 2, 1]
)
df.sort_index(axis=1, inplace=True)
print("Original df (now modified):")
print(df)Output:
Original df (now modified):
col1 col2
3 70 150
2 55 170
1 60 160Practical Example: Sorting a Real-World DataFrame
Here is a more realistic example with string indices and multiple columns:
import pandas as pd
sales = pd.DataFrame({
'Revenue': [50000, 62000, 48000, 71000],
'Expenses': [30000, 35000, 28000, 40000],
'Profit': [20000, 27000, 20000, 31000]
}, index=['Q3', 'Q1', 'Q4', 'Q2'])
print("Original:")
print(sales)
sorted_sales = sales.sort_index(axis=0).sort_index(axis=1)
print("\nSorted by both:")
print(sorted_sales)Output:
Original:
Revenue Expenses Profit
Q3 50000 30000 20000
Q1 62000 35000 27000
Q4 48000 28000 20000
Q2 71000 40000 31000
Sorted by both:
Expenses Profit Revenue
Q1 35000 27000 62000
Q2 40000 31000 71000
Q3 30000 20000 50000
Q4 28000 20000 48000Quarters are now in order (Q1–Q4) and columns are alphabetical (Expenses, Profit, Revenue).
Common Mistake: Forgetting to Capture the Result
A frequent error is calling sort_index() without assigning the result or using inplace=True:
import pandas as pd
df = pd.DataFrame({'B': [3, 1], 'A': [2, 4]}, index=[2, 1])
df.sort_index(axis=1)
print("df is still unsorted:")
print(df)Output:
df is still unsorted:
B A
2 3 2
1 1 4The correct approach
Either assign the result or use inplace=True:
df = df.sort_index(axis=1)
df.sort_index(axis=1, inplace=True)Quick Reference
| Goal | Code |
|---|---|
| Sort rows by index (ascending) | df.sort_index() |
| Sort rows by index (descending) | df.sort_index(ascending=False) |
| Sort columns by name (ascending) | df.sort_index(axis=1) |
| Sort columns by name (descending) | df.sort_index(axis=1, ascending=False) |
| Sort both rows and columns | df.sort_index().sort_index(axis=1) |
| Sort permanently | df.sort_index(inplace=True) |
| Sort by column values (not names) | df.sort_values(by='column_name') |
The sort_index() method gives you straightforward control over the ordering of your DataFrame's structural labels. By specifying the axis and direction, you can organize rows by index, columns by name, or both - ensuring your data is presented in a clean, predictable order.