pandas
python
dataframe
data-manipulation
coding-tutorial

How to delete the last row of data of a pandas dataframe

Master System Design with Codemia

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

Introduction

Removing the last row from a pandas DataFrame is simple, but there are still a few decisions hidden inside the task. You might want to drop the last row by position, drop the row whose index label happens to be last, or remove a trailing summary row while keeping real data intact. Using the right approach makes the code easier to read and safer when the DataFrame is empty or carries a meaningful index.

In day-to-day code, the most common answer is df.iloc[:-1]. That works well because pandas uses standard Python slice behavior, so the intent is obvious and the original DataFrame stays unchanged until you assign the result.

Remove the Last Row by Position

If you mean “keep everything except the final positional row,” iloc is usually the cleanest option. The iloc indexer is purely position-based, so [:-1] means start at the beginning and stop before the final row.

python
1import pandas as pd
2
3orders = pd.DataFrame(
4    {
5        "order_id": [101, 102, 103, 104],
6        "amount": [25.0, 40.5, 18.2, 99.9],
7    }
8)
9
10trimmed = orders.iloc[:-1]
11print(trimmed)

That produces a new DataFrame with the first three rows. The original orders variable is unchanged.

If you want the existing variable to refer to the shortened result, reassign it:

python
orders = orders.iloc[:-1].copy()

The .copy() call is useful when you plan to modify the result later. It makes the intent explicit and avoids confusion about whether later writes should affect a view or an independent object.

One nice detail is that slice indexing is forgiving. If the DataFrame is empty, df.iloc[:-1] still returns an empty DataFrame instead of raising an exception. That makes it a good default in ETL code where empty inputs are possible.

Drop the Final Index Label

Sometimes the index itself matters more than row position. In that case, it can be clearer to delete the last index label with drop.

python
1inventory = pd.DataFrame(
2    {"sku": ["A-1", "B-2", "C-3"]},
3    index=["row_10", "row_20", "row_30"],
4)
5
6result = inventory.drop(inventory.index[-1])
7print(result)

This is still removing the last row, but it describes the operation in label terms rather than slice terms. That reads well in code that already treats the index as part of the data model.

The main downside is that inventory.index[-1] fails if the frame is empty. A safe helper is easy to write:

python
1import pandas as pd
2
3def drop_last_row(frame: pd.DataFrame) -> pd.DataFrame:
4    if frame.empty:
5        return frame.copy()
6    return frame.drop(frame.index[-1])

Use this style when the last index label has meaning, or when the rest of the codebase already uses drop operations heavily.

Decide Whether to Reset the Index

After deleting the last row, ask whether the current index should stay as-is. pandas will preserve the remaining index values unless you reset them.

python
1sales = pd.DataFrame(
2    {"amount": [10, 20, 30, 40]},
3    index=[10, 11, 12, 13],
4)
5
6cleaned = sales.iloc[:-1].reset_index(drop=True)
7print(cleaned)

Reset the index when downstream code expects a simple 0..n-1 sequence. Keep the original index when it carries identity, timestamps, or keys used later in joins and debugging. There is no universal rule here; the correct choice depends on what the index represents.

This also matters in method chains. If the next step merges on index or serializes the frame, resetting too early can silently change semantics.

A lot of data-cleaning code says “remove the last row,” but what it actually means is “remove the trailing total row.” Those are different rules. If the last row is a footer, express that business rule instead of always chopping off the end.

python
1report = pd.DataFrame(
2    {
3        "label": ["North", "South", "TOTAL"],
4        "revenue": [1200, 900, 2100],
5    }
6)
7
8if not report.empty and report.iloc[-1]["label"] == "TOTAL":
9    report = report.iloc[:-1].copy()
10
11print(report)

That version is safer because it documents why the row is being removed. If the data source later stops appending a summary line, you do not accidentally delete a valid record.

Common Pitfalls

One common mistake is writing df.iloc[:-1] and assuming pandas modified the original DataFrame in place. It did not. You have to assign the result if you want the variable to change.

Another problem is using df.index[-1] on an empty frame. That raises an error, while df.iloc[:-1] on an empty frame is fine.

A third issue is resetting the index automatically even though the old index carried meaning. That can break joins, audit trails, or tests that compare index values directly.

Finally, avoid deleting the last row purely because a sample file once had a footer there. If the operation is really about a total row, encode that rule directly.

Summary

  • Use df.iloc[:-1] when you want the simplest positional solution.
  • Use df.drop(df.index[-1]) when index labels are the main thing you are working with.
  • Reassign the result because neither approach changes the original DataFrame automatically.
  • Reset the index only when downstream code needs a fresh positional index.
  • If the last row is a footer or total, remove it by business rule rather than by position alone.

Course illustration
Course illustration

All Rights Reserved.