pandas
dataframe
data manipulation
python
data analysis

Delete the first three rows of a dataframe in pandas

Master System Design with Codemia

Enhance your system design skills with over 120 practice problems, detailed solutions, and hands-on exercises.

Introduction

If you want to remove the first three rows of a pandas DataFrame, the cleanest solution is usually slicing with iloc. Whether you also reset the index depends on whether row labels still carry meaning in the rest of your pipeline.

The Simplest Approach: Slice From Row 3 Onward

When the goal is "drop the first three rows by position," slicing is direct and readable.

python
1import pandas as pd
2
3df = pd.DataFrame({
4    "name": ["a", "b", "c", "d", "e"],
5    "value": [10, 20, 30, 40, 50],
6})
7
8result = df.iloc[3:]
9print(result)

Output:

text
  name  value
3    d     40
4    e     50

iloc[3:] means "give me all rows from positional index 3 onward." Since pandas uses zero-based positions, that removes the first three rows.

Reset The Index If You Want A Fresh Table

After slicing, the original row labels remain. If you want the result to start at 0 again, reset the index.

python
1import pandas as pd
2
3df = pd.DataFrame({
4    "name": ["a", "b", "c", "d", "e"],
5    "value": [10, 20, 30, 40, 50],
6})
7
8result = df.iloc[3:].reset_index(drop=True)
9print(result)

Output:

text
  name  value
0    d     40
1    e     50

This is common when the old row labels are no longer meaningful and you want a clean sequential index for later processing.

drop Also Works, But Solves A Slightly Different Problem

You can also remove the first three rows using drop.

python
1import pandas as pd
2
3df = pd.DataFrame({
4    "name": ["a", "b", "c", "d", "e"],
5    "value": [10, 20, 30, 40, 50],
6})
7
8result = df.drop(df.index[:3])
9print(result)

This is useful when you are thinking in terms of row labels rather than position slicing, or when you want to generalize the same pattern to other subsets.

For this specific case, though, iloc[3:] is usually easier to read because it directly expresses "skip the first three rows by position."

Be Clear About Position Versus Label

This distinction matters a lot in pandas:

  • 'iloc is positional'
  • 'loc is label-based'
  • 'drop usually acts on labels unless you build those labels from position first'

That means df.iloc[3:] always means "rows after the first three positions," even if the index labels are unusual.

For example:

python
1import pandas as pd
2
3df = pd.DataFrame(
4    {"value": [10, 20, 30, 40, 50]},
5    index=[100, 101, 102, 103, 104],
6)
7
8print(df.iloc[3:])

This still returns the last two rows by position, even though the labels are 103 and 104.

That predictability is one reason iloc is usually the best answer here.

If You Need To Modify The Original Variable

Pandas slicing returns a new object reference. In most data pipelines, the simplest pattern is reassignment.

python
df = df.iloc[3:].reset_index(drop=True)

This is better than trying to force an in-place deletion for a small transformation. It keeps the code explicit and avoids confusion about whether the original object changed.

Handle Short DataFrames Safely

What if the DataFrame has fewer than three rows? The nice part is that slicing already behaves safely.

python
1import pandas as pd
2
3df = pd.DataFrame({"value": [10, 20]})
4print(df.iloc[3:])

This returns an empty DataFrame, not an error.

That makes slicing a robust default when the row count may vary.

When You Should Not Reset The Index

Resetting the index is convenient, but not always correct. If the index contains meaningful identifiers such as timestamps, database keys, or row lineage markers, dropping that information may be the wrong move.

For example, if the first three rows are headers or warm-up values and the index represents event time, you may want:

python
filtered = df.iloc[3:]

and not:

python
filtered = df.iloc[3:].reset_index(drop=True)

The transformation should match what the index means in the rest of the code.

Common Pitfalls

  • Using loc when the task is based on position, not label.
  • Resetting the index automatically even when the original index carries business meaning.
  • Assuming drop([0, 1, 2]) always means "first three rows" even when the index labels are not 0, 1, and 2.
  • Expecting slicing to modify the original DataFrame without reassignment.
  • Writing a loop to remove rows one by one instead of using vectorized slicing.

Summary

  • The simplest way to remove the first three rows is df.iloc[3:].
  • Add .reset_index(drop=True) if you want a fresh sequential index.
  • 'drop(df.index[:3]) also works, but is usually less direct for this case.'
  • Use positional logic for positional problems.
  • Decide consciously whether the original index should be preserved or discarded.

Course illustration
Course illustration

All Rights Reserved.