Python Pandas: How to Reset the Index of a Pandas DataFrame in Python
When you manipulate a Pandas DataFrame - by dropping rows, filtering, sorting, or slicing - the original index values are preserved. This can leave gaps in the index (e.g., 0, 3, 5, 7 instead of 0, 1, 2, 3), which can cause confusion and issues in downstream operations. The reset_index() method reassigns a clean, sequential integer index starting from 0.
In this guide, you will learn how to reset a DataFrame's index, control whether the old index is kept or discarded, and understand when resetting the index is necessary.
The Problem: Gaps in the Index After Dropping Rows
When you drop rows from a DataFrame, the index retains the original values:
import pandas as pd
df = pd.DataFrame({
'name': ['Jordan', 'Brady', 'James', 'Bryant',
'Rodriguez', 'Jeter', 'Williams', 'Ali',
'Phelps', 'Woods'],
'runs': [32292, 89214, 38652, 33643,
3115, 3465, 365, 56,
28, 82]
})
print("Original DataFrame:")
print(df)
Output:
Original DataFrame:
name runs
0 Jordan 32292
1 Brady 89214
2 James 38652
3 Bryant 33643
4 Rodriguez 3115
5 Jeter 3465
6 Williams 365
7 Ali 56
8 Phelps 28
9 Woods 82
After dropping rows at index 0 and 1:
df = df.drop([0, 1])
print("After dropping rows 0 and 1:")
print(df)
Output:
After dropping rows 0 and 1:
name runs
2 James 38652
3 Bryant 33643
4 Rodriguez 3115
5 Jeter 3465
6 Williams 365
7 Ali 56
8 Phelps 28
9 Woods 82
The index now starts at 2 instead of 0, and positions 0 and 1 are missing. This can cause issues with positional operations like iloc or when iterating with range(len(df)).
Resetting the Index With reset_index()
The reset_index() method creates a new sequential integer index:
import pandas as pd
df = pd.DataFrame({
'name': ['Jordan', 'Brady', 'James', 'Bryant',
'Rodriguez', 'Jeter', 'Williams', 'Ali',
'Phelps', 'Woods'],
'runs': [32292, 89214, 38652, 33643,
3115, 3465, 365, 56,
28, 82]
})
print("Original DataFrame:")
print(df)
print("\nAfter dropping rows 0 and 1:")
print(df)
# reset the index
df = df.reset_index(drop=True)
print("After resetting the index:")
print(df)
Output:
Original DataFrame:
name runs
0 Jordan 32292
1 Brady 89214
2 James 38652
3 Bryant 33643
4 Rodriguez 3115
5 Jeter 3465
6 Williams 365
7 Ali 56
8 Phelps 28
9 Woods 82
After dropping rows 0 and 1:
name runs
0 Jordan 32292
1 Brady 89214
2 James 38652
3 Bryant 33643
4 Rodriguez 3115
5 Jeter 3465
6 Williams 365
7 Ali 56
8 Phelps 28
9 Woods 82
After resetting the index:
name runs
0 Jordan 32292
1 Brady 89214
2 James 38652
3 Bryant 33643
4 Rodriguez 3115
5 Jeter 3465
6 Williams 365
7 Ali 56
8 Phelps 28
9 Woods 82
The index is now clean and sequential: 0, 1, 2, ..., 7.
Key Parameter: drop
The drop parameter controls what happens to the old index:
drop=True - Discard the Old Index
The old index is removed completely:
df_reset = df.reset_index(drop=True)
This is the most common usage when the old index has no meaningful information.
drop=False (Default) - Keep the Old Index as a Column
The old index is preserved as a new column named index:
import pandas as pd
df = pd.DataFrame({'value': [10, 20, 30]}, index=[5, 10, 15])
df_reset = df.reset_index() # drop=False by default
print(df_reset)
Output:
index value
0 5 10
1 10 20
2 15 30
The old index [5, 10, 15] is now a column called index.
Keep the old index (drop=False) when it contains meaningful data - for example, if the index represents dates, IDs, or category labels that you want to preserve as a regular column.
import pandas as pd
# Date index → keep as a column for analysis
df = pd.DataFrame({'price': [100, 105, 102]},
index=pd.to_datetime(['2024-01-01', '2024-01-02', '2024-01-03']))
df_reset = df.reset_index() # Old index becomes a 'index' column (or the index name)
print(df_reset)
Output:
index price
0 2024-01-01 100
1 2024-01-02 105
2 2024-01-03 102
Resetting the Index In Place
By default, reset_index() returns a new DataFrame. To modify the original DataFrame directly, use inplace=True:
df.reset_index(drop=True, inplace=True)
Using inplace=True modifies the original DataFrame and returns None. Do not assign the result to a variable:
# ❌ Wrong: result is None
df = df.reset_index(drop=True, inplace=True)
print(df) # None!
# ✅ Correct: either use inplace=True without assignment
df.reset_index(drop=True, inplace=True)
# ✅ Or assign without inplace
df = df.reset_index(drop=True)
Common Scenarios for Resetting the Index
After Filtering Rows
import pandas as pd
df = pd.DataFrame({
'name': ['Alice', 'Bob', 'Charlie', 'Diana', 'Eve'],
'score': [85, 42, 91, 67, 73]
})
# Filter for scores above 70
passed = df[df['score'] > 70]
print("Before reset:")
print(passed)
passed = passed.reset_index(drop=True)
print("\nAfter reset:")
print(passed)
Output:
Before reset:
name score
0 Alice 85
2 Charlie 91
4 Eve 73
After reset:
name score
0 Alice 85
1 Charlie 91
2 Eve 73
After Sorting
import pandas as pd
df = pd.DataFrame({
'name': ['Charlie', 'Alice', 'Bob'],
'score': [91, 85, 42]
})
df_sorted = df.sort_values('name').reset_index(drop=True)
print(df_sorted)
Output:
name score
0 Alice 85
1 Bob 42
2 Charlie 91
After Concatenation
import pandas as pd
df1 = pd.DataFrame({'value': [1, 2, 3]})
df2 = pd.DataFrame({'value': [4, 5, 6]})
combined = pd.concat([df1, df2])
print("Before reset:")
print(combined)
combined = combined.reset_index(drop=True)
print("\nAfter reset:")
print(combined)
Output:
Before reset:
value
0 1
1 2
2 3
0 4
1 5
2 6
After reset:
value
0 1
1 2
2 3
3 4
4 5
5 6
Without resetting, the concatenated DataFrame has duplicate index values (two 0s, two 1s, two 2s), which can cause unexpected behavior with loc[].
After GroupBy Aggregation
import pandas as pd
df = pd.DataFrame({
'department': ['Sales', 'Sales', 'Engineering', 'Engineering'],
'salary': [50000, 60000, 80000, 90000]
})
avg_salary = df.groupby('department')['salary'].mean().reset_index()
print(avg_salary)
Output:
department salary
0 Engineering 85000.0
1 Sales 55000.0
Without reset_index(), the department name would be the index, not a column.
Complete Example
import pandas as pd
# Create DataFrame
df = pd.DataFrame({
'name': ['Jordan', 'Brady', 'James', 'Bryant',
'Rodriguez', 'Jeter', 'Williams', 'Ali',
'Phelps', 'Woods'],
'runs': [32292, 89214, 38652, 33643,
3115, 3465, 365, 56,
28, 82]
})
print("Original DataFrame:")
print(df)
# Drop rows at index 0 and 1
df = df.drop([0, 1])
print("\nAfter dropping rows 0 and 1:")
print(df)
# Reset the index
df = df.reset_index(drop=True)
print("\nAfter resetting the index:")
print(df)
Output:
Original DataFrame:
name runs
0 Jordan 32292
1 Brady 89214
2 James 38652
3 Bryant 33643
4 Rodriguez 3115
5 Jeter 3465
6 Williams 365
7 Ali 56
8 Phelps 28
9 Woods 82
After dropping rows 0 and 1:
name runs
2 James 38652
3 Bryant 33643
4 Rodriguez 3115
5 Jeter 3465
6 Williams 365
7 Ali 56
8 Phelps 28
9 Woods 82
After resetting the index:
name runs
0 James 38652
1 Bryant 33643
2 Rodriguez 3115
3 Jeter 3465
4 Williams 365
5 Ali 56
6 Phelps 28
7 Woods 82
Quick Reference
| Scenario | Code |
|---|---|
| Reset and discard old index | df.reset_index(drop=True) |
| Reset and keep old index as column | df.reset_index() |
| Reset in place | df.reset_index(drop=True, inplace=True) |
| Reset after filtering | df[condition].reset_index(drop=True) |
| Reset after concat | pd.concat([df1, df2]).reset_index(drop=True) |
| Reset after groupby | df.groupby('col').agg(...).reset_index() |
Conclusion
The reset_index() method is essential for maintaining a clean, sequential index after operations that alter the DataFrame's structure, such as dropping rows, filtering, sorting, concatenating, or aggregating.
Use drop=True when the old index has no analytical value, and omit drop (or set it to False) when the old index contains meaningful data you want to preserve as a column.
Resetting the index prevents bugs caused by gaps, duplicates, or unexpected index values in downstream operations.