Inspecting Data: head, tail, info, describe

Reviewed & published by Brayan K

Inspecting data means using Pandas' built-in summary methods — head, tail, info, and describe — to get a fast, reliable overview of a dataset's contents, structure, and statistics before you analyse it.

Part of the free Pandas course at LearnCodingFast — hands-on lessons with examples you run in your browser, plus practice exercises and a quick quiz.

Never trust data you haven't looked at. These methods are the first thing every analyst runs on a fresh dataset.

What You'll Learn in This Lesson

1 Previewing Rows: head() and tail()

Real datasets can have thousands of rows. df.head() shows the first 5 and df.tail() shows the last 5 — a quick peek without flooding your screen:

df.head()      # first 5 rows
df.head(3)     # first 3 rows
df.tail(2)     # last 2 rows
import pandas as pd

df = pd.DataFrame({
    "name": ["Ana", "Ben", "Cara", "Dan", "Eve", "Finn"],
    "score": [88, 72, 95, 60, 79, 84],
})

print(df.head(3))    # first 3 rows
print(df.tail(2))    # last 2 rows

# Output:
#   name  score
# 0  Ana     88
# 1  Ben     72
# 2 Cara     95
#   name  score
# 4  Eve     79
# 5 Finn     84

# ✅ Expected output:
#    name  score
# 0   Ana     88
# 1   Ben     72
# 2  Cara     95
#    name  score
# 4   Eve     79
# 5  Finn     84

2 Structure: info(), shape, columns, dtypes

df.info() prints a compact summary of the DataFrame's structure: how many rows, each column's name, its non-null count (great for spotting missing data), and its dtype.

import pandas as pd

df = pd.DataFrame({
    "name": ["Ana", "Ben", "Cara"],
    "score": [88, 72, 95],
    "passed": [True, True, True],
})

df.info()

# Output:
# <class 'pandas.core.frame.DataFrame'>
# RangeIndex: 3 entries, 0 to 2
# Data columns (total 3 columns):
#  #   Column  Non-Null Count  Dtype
# ---  ------  --------------  -----
#  0   name    3 non-null      object
#  1   score   3 non-null      int64
#  2   passed  3 non-null      bool
# dtypes: bool(1), int64(1), object(1)
# memory usage: 179.0+ bytes

# ✅ Expected output:
# <class 'pandas.core.frame.DataFrame'>
# RangeIndex: 3 entries, 0 to 2
# Data columns (total 3 columns):
#  #   Column  Non-Null Count  Dtype 
# ---  ------  --------------  ----- 
#  0   name    3 non-null      object
#  1   score   3 non-null      int64 
#  2   passed  3 non-null      bool  
# dtypes: bool(1), int64(1), object(1)
# memory usage: 183.0+ bytes

3 Statistics: describe(), nunique(), value_counts()

df.describe() computes summary statistics for every numeric column — count, mean, standard deviation, min, the three quartiles, and max:

df.describe()                 # numeric summary stats
df.nunique()                  # distinct values per column
df["city"].value_counts()     # tally of each category

nunique() tells you how many distinct values a column has, while value_counts() tallies how many times each value appears — ideal for category columns.

import pandas as pd

df = pd.DataFrame({
    "city": ["London", "Paris", "London", "Berlin", "Paris", "London"],
    "temp": [15, 18, 14, 12, 19, 16],
})

print(df["city"].value_counts())   # tally each city
print()
print("Distinct cities:", df["city"].nunique())
print("Mean temp:", df["temp"].mean())

# Output:
# city
# London    3
# Paris     2
# Berlin    1
# Name: count, dtype: int64
#
# Distinct cities: 3
# Mean temp: 15.666666666666666

# ✅ Expected output:
# city
# London    3
# Paris     2
# Berlin    1
# Name: count, dtype: int64
#
# Distinct cities: 3
# Mean temp: 15.666666666666666
import pandas as pd

df = pd.DataFrame({
    "name": ["Ana", "Ben", "Cara", "Dan"],
    "score": [88, 72, 95, 60],
})

# 🎯 YOUR TURN: print the numeric summary statistics
# Replace ___ with the right method name
print(df.___())

# Expected output (rows: count, mean, std, min, 25%, 50%, 75%, max):
#            score
# count   4.000000
# mean   78.750000
# std    15.305773
# min    60.000000
# 25%    69.000000
# 50%    80.000000
# 75%    89.750000
# max    95.000000

📋 Quick Reference

MethodTells You
df.head() / df.tail()First / last rows
df.shape(rows, columns)
df.info()Types, non-null counts, memory
df.describe()Numeric summary statistics
df.nunique()Distinct values per column
df["col"].value_counts()Tally of each value

🎯 Mini Challenge: Quick Audit

Run a four-step audit on a small dataset:

import pandas as pd

df = pd.DataFrame({
    "player": ["Ana", "Ben", "Cara", "Dan"],
    "team": ["Red", "Blue", "Red", "Blue"],
    "points": [10, 7, 13, 9],
})

print("Shape:", df.shape)
print(df.head(2))
print(df["team"].value_counts())

# Output:
# Shape: (4, 3)
#   player  team  points
# 0    Ana   Red      10
# 1    Ben  Blue       7
# team
# Red     2
# Blue    2
# Name: count, dtype: int64

# ✅ Expected output:
# Shape: (4, 3)
#   player  team  points
# 0    Ana   Red      10
# 1    Ben  Blue       7
# team
# Red     2
# Blue    2
# Name: count, dtype: int64

❓ Frequently Asked Questions

Lesson complete — you can audit any dataset!

You can preview rows with head and tail, check structure and missing data with info, summarise numbers with describe, and tally categories with nunique and value_counts.

Practice quiz

How many rows does df.head() show by default?

  • 10
  • 5
  • 3
  • All of them

Answer: 5. df.head() returns the first 5 rows by default.

What does df.tail(2) return?

  • The first 2 rows
  • Every other row
  • The last 2 rows
  • 2 random rows

Answer: The last 2 rows. tail(n) shows the last n rows; tail(2) shows the final two.

Which method summarises structure: column names, non-null counts, and dtypes?

  • df.describe()
  • df.head()
  • df.value_counts()
  • df.info()

Answer: df.info(). df.info() reports structure, non-null counts, dtypes, and memory usage.

Which method gives count, mean, std, min, quartiles, and max for numeric columns?

  • df.describe()
  • df.info()
  • df.shape
  • df.head()

Answer: df.describe(). df.describe() computes summary statistics for numeric columns.

What does df.shape return?

  • The column names
  • A tuple of (rows, columns)
  • The dtypes
  • The memory usage

Answer: A tuple of (rows, columns). df.shape is a (rows, columns) tuple.

What does df['col'].value_counts() do?

  • Returns the column mean
  • Sorts the column
  • Tallies how many times each distinct value appears
  • Counts the columns

Answer: Tallies how many times each distinct value appears. value_counts() counts occurrences of each value, sorted high to low.

What does df.nunique() report?

  • The total row count
  • The mean of each column
  • The sum per column
  • The number of distinct values per column

Answer: The number of distinct values per column. nunique() returns how many distinct values each column has.

What does df.info() return as its value?

  • None (it prints the summary)
  • A DataFrame
  • A dictionary
  • A list of dtypes

Answer: None (it prints the summary). info() prints its summary and returns None, so do not assign its result.

For scores [88, 72, 95, 60], what mean does describe() report?

  • 78.75
  • 80.0
  • 72.0
  • 95.0

Answer: 78.75. (88+72+95+60)/4 = 78.75.

What is the recommended first pair of methods to run on a new dataset?

  • df.melt() and df.pivot()
  • df.groupby() and df.agg()
  • df.shape and df.head()
  • df.drop() and df.fillna()

Answer: df.shape and df.head(). Start with df.shape and df.head() to see the size and a sample.

Continue this course

Frequently asked questions

What does df.head() do in Pandas?

df.head() returns the first 5 rows of a DataFrame so you can preview its contents without printing everything. Pass a number to change how many, e.g. df.head(10). df.tail() does the same for the last rows.

What is the difference between info() and describe()?

df.info() summarises structure — column names, non-null counts, dtypes, and memory usage. df.describe() summarises the numbers — count, mean, std, min, quartiles, and max for each numeric column. One is about shape, the other about statistics.

How do I count unique values in a column?

Use df['col'].value_counts() to count how many times each distinct value appears (sorted high to low), or df.nunique() to get just the number of distinct values per column.

Which inspection method should I run first on a new dataset?

Start with df.shape and df.head() to see the size and a sample, then df.info() to check types and missing values, and df.describe() to understand the numeric ranges. Those four give you a fast, reliable overview.