Skip to content

Python Pandas: How to Reset the Index of a Pandas DataFrame in Python

Learn how to use Pandas' reset_index() method to fix gaps, duplicates, or non-sequential indices after dropping rows, filtering, sorting, or concatenating DataFrames 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)

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.

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)

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]
})

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

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)

df = df.drop([0, 1])
print("\nAfter dropping rows 0 and 1:")
print(df)

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.

Navigation