pandas
DataFrame
Python
data analysis
coding

How to get the last N rows of a pandas DataFrame?

ML System Design practice on Codemia

Design recommenders, ranking systems and training pipelines the way ML interviews actually ask for them, with worked solutions.

Practice ML system design

Introduction

Getting the last N rows of a pandas DataFrame is a routine operation when you inspect recent records, debug a transformation, or preview the end of a dataset. Pandas makes this easy with .tail(), and it also offers indexing-based alternatives when you need more control.

The Standard Solution: tail

The most direct method is DataFrame.tail(n).

python
1import pandas as pd
2
3df = pd.DataFrame(
4    {
5        "day": ["Mon", "Tue", "Wed", "Thu", "Fri"],
6        "sales": [10, 12, 9, 14, 11],
7    }
8)
9
10print(df.tail(2))

Output:

text
   day  sales
3  Thu     14
4  Fri     11

tail(2) returns the last two rows in their original order. If you omit the argument, pandas returns the last five rows by default.

Using iloc Slicing

You can achieve the same result with integer-location indexing:

python
print(df.iloc[-2:])

This is useful when you are already working with iloc and want slicing syntax for consistency. It behaves similarly to Python list slicing from the end.

What Happens When N Is Large

Both .tail(n) and df.iloc[-n:] are forgiving when n is larger than the DataFrame length. Instead of raising an error, pandas returns the whole DataFrame.

python
print(df.tail(10))

That behavior is convenient in reporting code because you do not need a separate bounds check for many cases.

When "Last" Does Not Mean "Latest"

A common conceptual bug is assuming the last rows are the most recent rows. Pandas preserves row order; it does not automatically sort by time. If your data is not already ordered by a timestamp, sort first and then take the tail.

python
1df["created_at"] = pd.to_datetime(
2    ["2024-01-03", "2024-01-01", "2024-01-05", "2024-01-02", "2024-01-04"]
3)
4
5latest_rows = df.sort_values("created_at").tail(2)
6print(latest_rows)

Without the sort, you would only get the last rows in current storage order, which may not match the latest timestamps.

Resetting the Index if Needed

The returned slice keeps the original index values. That is usually correct, but sometimes you want a clean zero-based index for display or downstream processing.

python
recent = df.tail(2).reset_index(drop=True)
print(recent)

Use this only when reindexing is desirable. Preserving the original index can be important for joins or debugging.

Last Rows Within Each Group

Sometimes you do not want the last N rows of the whole DataFrame. You want the last row or last few rows inside each group, such as the latest record per customer. In that case, combine grouping with .tail().

python
1orders = pd.DataFrame(
2    {
3        "customer": ["A", "A", "B", "B", "B"],
4        "order_id": [101, 102, 201, 202, 203],
5    }
6)
7
8latest_per_customer = orders.groupby("customer").tail(1)
9print(latest_per_customer)

This is a different problem from taking the final rows of the full DataFrame, but it uses the same tail concept and is worth keeping in mind.

Choosing Between tail and iloc

For readability, .tail(n) is usually the best choice because it states the intent directly. iloc is more flexible when you are composing larger index-based selections.

In other words:

  • use .tail(n) for clarity
  • use iloc when you are already in an index-slicing workflow

Both are efficient enough for ordinary DataFrame inspection and transformation tasks.

Common Pitfalls

Assuming the last rows are the newest rows without sorting by a timestamp can give misleading results.

Forgetting that the original index is preserved can be confusing when the slice prints row labels such as 98 and 99.

Passing a negative n changes the semantics in ways many people do not intend, so keep the argument positive for "last N rows" logic.

Using label-based .loc instead of .iloc for negative slicing will not behave the same way.

Overcomplicating the task with manual loops is unnecessary because pandas already has a direct built-in method.

Summary

  • Use df.tail(n) to get the last N rows of a DataFrame.
  • 'df.iloc[-n:] is the equivalent indexing-based form.'
  • If n exceeds the DataFrame length, pandas returns all rows.
  • Sort by a time column first if "last" should mean "latest".
  • Reset the index only when you want a fresh sequential display.

Related reading
Free course
Beginner
7 lessons
2 hours
Tackling System Design Interview Problems

A short course that equips you with the skills to approach system design interviews methodically.

Start the free course
Track what you have practised

A free account saves your progress, solutions and study plan across every problem on Codemia.

ML System Design practice on Codemia

Design recommenders, ranking systems and training pipelines the way ML interviews actually ask for them, with worked solutions.

Practice ML system design

All Rights Reserved.