Pandas tail(): Last Rows and Latest Order Previews

Use tail() to preview the last rows in the current order. Inspect imported files and sort validated dates before selecting recent records.

Create the student table 🔝

tail() selects rows by position in their current order. It does not sort them or find the latest dates automatically.

import pandas as pd
from io import StringIO, BytesIO

students = pd.DataFrame({
    "NAME": ["Ravi", "Raju", "Alex", "Ron", "King", "Jack"],
    "ID": [1, 2, 3, 4, 5, 6],
    "MATH": [80, 40, 70, 70, 60, 30],
    "ENGLISH": [80, 70, 40, 50, 60, 30]
})
print(students)

Expected output

   NAME  ID  MATH  ENGLISH
0  Ravi   1    80       80
1  Raju   2    40       70
2  Alex   3    70       40
3   Ron   4    70       50
4  King   5    60       60
5  Jack   6    30       30

Return the last five rows 🔝

The default n is 5. Existing index labels and columns are preserved. A table with fewer rows returns all available rows.

print(students.tail())
assert students.tail()["ID"].tolist() == [2, 3, 4, 5, 6]

Expected output

   NAME  ID  MATH  ENGLISH
1  Raju   2    40       70
2  Alex   3    70       40
3   Ron   4    70       50
4  King   5    60       60
5  Jack   6    30       30

Choose the number of final rows 🔝

Pass an integer to choose a preview size. A Series caller returns a Series; a DataFrame caller returns a DataFrame.

print(students.tail(2))
print("Names:")
print(students["NAME"].tail(2))
assert students.tail(2)["NAME"].tolist() == ["King", "Jack"]

Expected output

   NAME  ID  MATH  ENGLISH
4  King   5    60       60
5  Jack   6    30       30
Names:
4    King
5    Jack
Name: NAME, dtype: str

Use a negative count to omit initial rows 🔝

tail(-1) keeps every row after the first. A negative n excludes the first absolute n rows, rather than selecting that many final rows.

print(students.tail(-1))
assert students.tail(-1)["ID"].tolist() == [2, 3, 4, 5, 6]
assert students.tail(-2)["ID"].tolist() == [3, 4, 5, 6]

Expected output

   NAME  ID  MATH  ENGLISH
1  Raju   2    40       70
2  Alex   3    70       40
3   Ron   4    70       50
4  King   5    60       60
5  Jack   6    30       30

Handle zero and oversized counts 🔝

tail(0) is empty but retains the columns. An oversized positive count returns the full table; a negative count whose magnitude exceeds the row count returns an empty table.

for n in [0, 20, -20]:
    preview = students.tail(n)
    print("n:", n, "Rows:", len(preview), "IDs:", preview["ID"].tolist())
assert students.tail(0).columns.equals(students.columns)
assert len(students.tail(20)) == 6

Expected output

n: 0 Rows: 0 IDs: []
n: 20 Rows: 6 IDs: [1, 2, 3, 4, 5, 6]
n: -20 Rows: 0 IDs: []

Distinguish row positions from labels 🔝

tail() works with nonsequential labels too. iloc uses positional slicing with square brackets. For n=0, tail(0) is empty while iloc[-0:] selects all rows, because -0 equals 0.

indexed = students.set_index("ID")
print(indexed.tail(2))
print("Matches positional slice:", indexed.tail(2).equals(indexed.iloc[-2:]))
assert indexed.tail(2).equals(indexed.iloc[-2:])
assert len(indexed.iloc[-0:]) == 6
assert len(indexed.tail(0)) == 0

Expected output

    NAME  MATH  ENGLISH
ID                     
5   King    60       60
6   Jack    30       30
Matches positional slice: True

Inspect the end of an imported CSV 🔝

The embedded CSV runs without a local file. Replace StringIO(csv_text) with your path or URL. A Windows path can use a raw string such as r"D:\my_data\student.csv". Calling tail() after reading still loads the full CSV. See read_csv().

csv_text = students.to_csv(index=False)
from_csv = pd.read_csv(StringIO(csv_text))
print(from_csv.tail(2))
print("Full shape:", from_csv.shape)
assert from_csv.shape == (6, 4)

Expected output

   NAME  ID  MATH  ENGLISH
4  King   5    60       60
5  Jack   6    30       30
Full shape: (6, 4)

Inspect an Excel sheet and its dimensions 🔝

The in-memory workbook demonstrates read_excel() without an upload. Excel needs an engine such as openpyxl; this example explains a missing dependency and lets the rest of the notebook continue. See read_excel() and to_excel().

try:
    import openpyxl
except ImportError:
    print("Excel example requires openpyxl; continue with the CSV examples.")
else:
    workbook = BytesIO()
    students.rename(columns={"ID": "id"}).to_excel(workbook, index=False, engine="openpyxl")
    workbook.seek(0)
    from_excel = pd.read_excel(workbook, index_col="id", engine="openpyxl")
    print(from_excel.tail(2))
    print("Full shape:", from_excel.shape)
    assert from_excel.shape == (6, 3)

Expected output

    NAME  MATH  ENGLISH
id                     
5   King    60       60
6   Jack    30       30
Full shape: (6, 3)

Format a text preview with full row counts 🔝

shape is an attribute, not a function. to_string() converts the last rows into display text. The count describes the full table, not only the preview.

summary = "Rows:" + str(students.shape[0]) + ",Columns:" + str(students.shape[1])
summary += "\n" + students.tail(2).to_string()
print(summary)
assert summary.startswith("Rows:6,Columns:4")

Expected output

Rows:6,Columns:4
   NAME  ID  MATH  ENGLISH
4  King   5    60       60
5  Jack   6    30       30

Compare head(), tail() and random sampling 🔝

head() inspects the start; tail() inspects the end. sample() selects random rows. None of these previews proves that every record is valid.

print("First IDs:", students.head(2)["ID"].tolist())
print("Last IDs:", students.tail(2)["ID"].tolist())
print("Sample IDs:", students.sample(n=2, random_state=42)["ID"].tolist())

Expected output

First IDs: [1, 2]
Last IDs: [5, 6]
Sample IDs: [1, 2]

Practical example: find the latest orders 🔝

This synthetic sales table arrives out of date order and includes an invalid date. Parse dates, retain invalid records for review and sort known dates before taking a latest-order preview. Use order_id to break ties deterministically.

raw = pd.DataFrame({
    "order_id": [101, 102, 103, 104, 105, 106],
    "date": ["2026-09-05", "2026-09-01", "bad", "2026-09-03", "2026-09-05", "2026-09-02"],
    "amount": [20, 10, 99, 15, 30, 12]
})
parsed = pd.to_datetime(raw["date"], errors="coerce")
review = raw.loc[parsed.isna()].copy()
valid = raw.loc[parsed.notna()].copy()
valid["date"] = parsed.loc[valid.index]
ordered = valid.sort_values(["date", "order_id"])
print("Original final IDs:", raw.tail(2)["order_id"].tolist())
print("Date review:")
print(review)
print("Ordered records:")
print(ordered)
assert review["order_id"].tolist() == [103]

Expected output

Original final IDs: [105, 106]
Date review:
   order_id date  amount
2       103  bad      99
Ordered records:
   order_id       date  amount
1       102 2026-09-01      10
5       106 2026-09-02      12
3       104 2026-09-03      15
0       101 2026-09-05      20
4       105 2026-09-05      30

Select latest records under a defined rule 🔝

Sort ascending then tail(2) selects the final two records. The preview stays in ascending order; sort the selected rows descending if you want newest first. This selects two records, not two distinct dates. See sort_values() and to_datetime().

latest = ordered.tail(2)
print("Latest records:")
print(latest)
print("Newest first:")
print(latest.sort_values(["date", "order_id"], ascending=[False, False]))
assert latest["order_id"].tolist() == [101, 105]

Expected output

Latest records:
   order_id       date  amount
0       101 2026-09-05      20
4       105 2026-09-05      30
Newest first:
   order_id       date  amount
4       105 2026-09-05      30
0       101 2026-09-05      20

Keep preview totals separate from full totals 🔝

Latest-order revenue is 50; revenue for all five known-date orders is 87. The invalid-date row remains in review. Report the population behind each total. Continue with Data Cleaning and sum().

print("Known-date orders:", len(ordered), "Review rows:", len(review))
print("All known-date revenue:", ordered["amount"].sum())
print("Latest preview revenue:", latest["amount"].sum())
assert len(ordered) + len(review) == len(raw)
assert ordered["amount"].sum() == 87
assert latest["amount"].sum() == 50

Expected output

Known-date orders: 5 Review rows: 1
All known-date revenue: 87
Latest preview revenue: 50

Export the intended selection 🔝

Export ordered for all known-date records, or latest for an explicitly named latest-order report. Keep order_id as a column; reset disposable row labels only if needed. See Input and Output and reset_index().

print(latest.to_csv(index=False).rstrip())
print("Export rows:", len(latest))
assert len(latest) == 2
# Optional Colab exports:
# latest.to_csv("latest_two_orders.csv", index=False)
# ordered.to_csv("all_known_date_orders.csv", index=False)

Expected output

order_id,date,amount

101,2026-09-05,20

105,2026-09-05,30
Export rows: 2

Common questions 🔝

Does tail() find recent dates? Only after a suitable sort. Does it reverse rows? No; selected rows retain their order. Does it change the source? No. Why are fewer rows returned? The source may be smaller than n. Why does tail(-2) return more than two rows? It excludes the first two. Does inspecting the end validate the whole file? No; check missing values, types and rules across the full table. Continue practising with shape and size, info(), text-match counts, student exercises and sample student files.

Exercise: select the latest two valid orders 🔝

Create IDs 1, 2 and 3 with dates September 3, September 1 and September 2 of 2026 and amounts 30, 10 and 20. Sort by date, preview the latest two and calculate their total.

Exercise solution 🔝

The latest two records are IDs 3 and 1 in ascending date order, with total 50.

practice = pd.DataFrame({
    "id": [1, 2, 3],
    "date": pd.to_datetime(["2026-09-03", "2026-09-01", "2026-09-02"]),
    "amount": [30, 10, 20]
})
answer = practice.sort_values(["date", "id"]).tail(2)
print(answer)
print("Latest total:", answer["amount"].sum())
assert answer["id"].tolist() == [3, 1]
assert answer["amount"].sum() == 50

Expected output

   id       date  amount
2   3 2026-09-02      20
0   1 2026-09-03      30
Latest total: 50

Practice in Google Colab 🔝

Open in Google Colab View on GitHub
Run the examples in order, change dates and preview sizes, then compare final rows with latest orders. Save your own copy to keep edits. All sample tables are included in the notebook.

Reference: Pandas DataFrame.tail documentation.




Subscribe to our YouTube Channel here



plus2net.com







Python Video Tutorials
Python SQLite Video Tutorials
Python MySQL Video Tutorials
Python Tkinter Video Tutorials
✖
We use cookies to improve your browsing experience. . Learn more
HTML MySQL PHP JavaScript ASP Photoshop Articles Contact us
© 2000-2026 plus2net.com All rights reserved worldwide Privacy Policy Disclaimer