Python Pandas: How to Reverse Rows in a Pandas DataFrame in Python
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
Method 1: Using iloc[::-1] (Recommended)
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.
iloc[::-1] is the recommended approach for most use cases. It's concise, efficient, and clearly communicates intent. It works the same way as reversing a Python list with list[::-1].
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:
ilocuses integer positions (0, 1, 2, ...).locuses 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
drop=True?Without drop=True, the old index is added as a new column in the DataFrame:
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)
# Without drop=True, old index becomes a column
reversed_df = df.iloc[::-1].reset_index()
print(reversed_df)
Output:
index Name Income Expenses Profit
0 3 Diana 95000 50000 6000
1 2 Charlie 110000 7000 4000
2 1 Bob 130000 11000 2000
3 0 Alice 150000 10000 5000
Set drop=True to discard the old index entirely.
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]
})
# Reverse in place
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]
# ❌ Confusing: iloc[0] returns the FIRST row of the reversed DataFrame
# but the index label is 3
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]})
# ✅ Reset index for consistent behavior
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,
ilocandlocbehave differently unless you reset the index.
All methods return a new DataFrame without modifying the original unless you explicitly reassign it.