Skip to content

Python Pandas: How to Reverse Rows in a Pandas DataFrame in Python

Learn how to reverse rows in a Pandas DataFrame using Python methods like iloc[::-1], loc[::-1], and sort_index(), with explanations of index behavior and best practices.

Reversing the order of rows in a DataFrame is a common operation in data analysis. You might need to flip your data to display the most recent entries first, reverse a time series for backward analysis, or simply reorder records for presentation purposes. Pandas provides several straightforward methods to achieve this.

In this guide, you'll learn multiple ways to reverse rows in a Pandas DataFrame, understand how each method handles the index, and choose the right approach for your use case.

Creating a Sample DataFrame

Let's start with a simple DataFrame to demonstrate all the methods:

import pandas as pd

data = {
    'Name': ['Alice', 'Bob', 'Charlie', 'Diana'],
    'Income': [150000, 130000, 110000, 95000],
    'Expenses': [10000, 11000, 7000, 50000],
    'Profit': [5000, 2000, 4000, 6000]
}

df = pd.DataFrame(data)
print(df)

Output:

      Name  Income  Expenses  Profit
0    Alice  150000     10000    5000
1      Bob  130000     11000    2000
2  Charlie  110000      7000    4000
3    Diana   95000     50000    6000

The simplest and most Pythonic way to reverse rows is using iloc with Python's slice notation [::-1]:

import pandas as pd

data = {
    'Name': ['Alice', 'Bob', 'Charlie', 'Diana'],
    'Income': [150000, 130000, 110000, 95000],
    'Expenses': [10000, 11000, 7000, 50000],
    'Profit': [5000, 2000, 4000, 6000]
}
df = pd.DataFrame(data)

reversed_df = df.iloc[::-1]
print(reversed_df)

Output:

      Name  Income  Expenses  Profit
3    Diana   95000     50000    6000
2  Charlie  110000      7000    4000
1      Bob  130000     11000    2000
0    Alice  150000     10000    5000

Notice that the original index is preserved - the rows are reversed but their index labels (3, 2, 1, 0) stay with their respective data.

Method 2: Using loc[::-1]

The loc accessor works similarly to iloc when used with slice notation:

import pandas as pd

data = {
    'Name': ['Alice', 'Bob', 'Charlie', 'Diana'],
    'Income': [150000, 130000, 110000, 95000],
    'Expenses': [10000, 11000, 7000, 50000],
    'Profit': [5000, 2000, 4000, 6000]
}
df = pd.DataFrame(data)

reversed_df = df.loc[::-1]
print(reversed_df)

Output:

      Name  Income  Expenses  Profit
3    Diana   95000     50000    6000
2  Charlie  110000      7000    4000
1      Bob  130000     11000    2000
0    Alice  150000     10000    5000

The result is identical to iloc[::-1]. The difference between loc and iloc matters more when selecting specific rows or columns:

  • iloc uses integer positions (0, 1, 2, ...).
  • loc uses index labels (which may be strings, dates, etc.).

For simple row reversal with a default integer index, both produce the same result.

Method 3: Using Direct Slicing df[::-1]

You can also reverse rows by slicing the DataFrame directly without loc or iloc:

import pandas as pd

data = {
    'Name': ['Alice', 'Bob', 'Charlie', 'Diana'],
    'Income': [150000, 130000, 110000, 95000],
    'Expenses': [10000, 11000, 7000, 50000],
    'Profit': [5000, 2000, 4000, 6000]
}
df = pd.DataFrame(data)

reversed_df = df[::-1]
print(reversed_df)

Output:

      Name  Income  Expenses  Profit
3    Diana   95000     50000    6000
2  Charlie  110000      7000    4000
1      Bob  130000     11000    2000
0    Alice  150000     10000    5000

This is the most concise syntax, though iloc[::-1] is generally preferred for clarity.

Method 4: Reversing and Resetting the Index

After reversing, the index is in descending order (3, 2, 1, 0). If you want a clean, sequential index starting from 0, use reset_index():

import pandas as pd

data = {
    'Name': ['Alice', 'Bob', 'Charlie', 'Diana'],
    'Income': [150000, 130000, 110000, 95000],
    'Expenses': [10000, 11000, 7000, 50000],
    'Profit': [5000, 2000, 4000, 6000]
}
df = pd.DataFrame(data)

reversed_df = df.iloc[::-1].reset_index(drop=True)
print(reversed_df)

Output:

      Name  Income  Expenses  Profit
0    Diana   95000     50000    6000
1  Charlie  110000      7000    4000
2      Bob  130000     11000    2000
3    Alice  150000     10000    5000

Method 5: Using reindex()

The reindex() method lets you rearrange rows according to a new index order:

import pandas as pd

data = {
    'Name': ['Alice', 'Bob', 'Charlie', 'Diana'],
    'Income': [150000, 130000, 110000, 95000],
    'Expenses': [10000, 11000, 7000, 50000],
    'Profit': [5000, 2000, 4000, 6000]
}
df = pd.DataFrame(data)

reversed_df = df.reindex(index=df.index[::-1])
print(reversed_df)

Output:

      Name  Income  Expenses  Profit
3    Diana   95000     50000    6000
2  Charlie  110000      7000    4000
1      Bob  130000     11000    2000
0    Alice  150000     10000    5000

This method is more verbose but useful when you need to reorder rows based on a custom index sequence, not just a simple reversal.

Method 6: Using sort_index(ascending=False)

If your DataFrame has a meaningful index (like dates or sequential IDs), you can reverse it by sorting the index in descending order:

import pandas as pd

data = {
    'Name': ['Alice', 'Bob', 'Charlie', 'Diana'],
    'Income': [150000, 130000, 110000, 95000],
    'Expenses': [10000, 11000, 7000, 50000],
    'Profit': [5000, 2000, 4000, 6000]
}
df = pd.DataFrame(data)

reversed_df = df.sort_index(ascending=False)
print(reversed_df)

Output:

      Name  Income  Expenses  Profit
3    Diana   95000     50000    6000
2  Charlie  110000      7000    4000
1      Bob  130000     11000    2000
0    Alice  150000     10000    5000

This is particularly useful with DatetimeIndex DataFrames:

import pandas as pd

dates_df = pd.DataFrame({
    'Sales': [100, 200, 150, 300]
}, index=pd.date_range('2025-01-01', periods=4))

print("Original:")
print(dates_df)

print("\nReversed (most recent first):")
print(dates_df.sort_index(ascending=False))

Output:

Original:
            Sales
2025-01-01    100
2025-01-02    200
2025-01-03    150
2025-01-04    300

Reversed (most recent first):
            Sales
2025-01-04    300
2025-01-03    150
2025-01-02    200
2025-01-01    100

Reversing Rows In Place

All the methods above return a new DataFrame without modifying the original. If you want to reverse the original DataFrame in place, reassign it:

import pandas as pd

df = pd.DataFrame({
    'Name': ['Alice', 'Bob', 'Charlie'],
    'Score': [85, 92, 78]
})

df = df.iloc[::-1].reset_index(drop=True)
print(df)

Output:

      Name  Score
0  Charlie     78
1      Bob     92
2    Alice     85

Common Mistake: Forgetting to Reset the Index

A common issue is performing operations on a reversed DataFrame without resetting the index, which can lead to confusing behavior when accessing rows by position:

import pandas as pd

df = pd.DataFrame({'Value': [10, 20, 30, 40]})
reversed_df = df.iloc[::-1]

print("iloc[0]:", reversed_df.iloc[0]['Value'])   # 40
print("loc[0]: ", reversed_df.loc[0]['Value'])    # 10 (original row 0!)

Output:

iloc[0]: 40
loc[0]:  10

After reversing, iloc[0] gives the first row of the reversed order (value 40), while loc[0] still accesses index label 0 (value 10). Reset the index if this distinction causes confusion:

import pandas as pd

df = pd.DataFrame({'Value': [10, 20, 30, 40]})


reversed_df = df.iloc[::-1].reset_index(drop=True)
print("iloc[0]:", reversed_df.iloc[0]['Value'])   # 40
print("loc[0]: ", reversed_df.loc[0]['Value'])    # 40 (same row now)

Output:

iloc[0]: 40
loc[0]:  40

Comparison of Methods

Method Syntax Preserves Original Index Best For
iloc[::-1] df.iloc[::-1] ✅ General-purpose reversal (recommended)
loc[::-1] df.loc[::-1] ✅ Same as iloc for default index
Direct slicing df[::-1] ✅ Most concise syntax
reset_index() df.iloc[::-1].reset_index(drop=True) ❌ (resets) Clean sequential index needed
reindex() df.reindex(index=df.index[::-1]) ✅ Custom index reordering
sort_index() df.sort_index(ascending=False) ✅ Reversing by meaningful index (dates, IDs)

Summary

To reverse rows in a Pandas DataFrame:

  • Use df.iloc[::-1] for the simplest, most readable approach - it works in all cases and is the recommended default.
  • Chain .reset_index(drop=True) if you need a clean, sequential index starting from 0.
  • Use sort_index(ascending=False) when working with meaningful indices like dates.
  • Be aware that after reversing, iloc and loc behave differently unless you reset the index.

All methods return a new DataFrame without modifying the original unless you explicitly reassign it.

Navigation