Skip to content

Python Pandas: How to Sort a Pandas DataFrame by Both Index and Column

Learn how to sort a Pandas DataFrame by row index, column names, or both simultaneously using sort_index() with clear examples and best practices.

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    60

The 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    70

Rows 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    60

Sorting 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   160

The 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   150

Both 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    60

Permanent 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   160

Practical 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    48000

Quarters 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  4

The 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.

Navigation