Data handling is the process of collecting, cleaning, transforming, and summarising data so that it can be analysed and understood. In the earlier Pandas chapters we learned to create Series and DataFrames and to apply basic operations such as sorting, grouping, and merging. Data Handling using Pandas takes that foundation and applies it to realistic data problems: inspecting a dataset, computing new columns from existing ones, removing duplicates, reshaping tables, and writing complete data-handling programs that read a file, process it, and produce a report.
The chapter is organised around the operations a working data analyst performs most often. We begin with the tools for understanding a new dataset, then move through column computation, user-defined functions, duplicate detection, and table reshaping with pivot tables. We also revisit filtering and slicing in greater depth, since precise row and column selection is the heart of practical data handling, and we end with a complete case study that ties every step together.
For the examination, this chapter is the bridge between the theory of Pandas and the practical file work that carries significant marks. Programs here combine reading a CSV, cleaning the data, computing derived columns, grouping the results, and printing a readable summary. Practising these complete workflows, rather than isolated commands, is the best preparation for both the practical examination and the case-based questions in the theory paper.
Before any analysis, a dataset must be inspected to understand its structure, size, and quality.
import pandas as pd
df = pd.read_csv("students.csv")
print(df.info())
print(df.describe())
print(df.shape)
print(df.columns)
print(df.isnull().sum())
df.info() prints the number of rows, column names, non-null counts, and data types.df.describe() summarises the numerical columns.df.isnull().sum() gives the count of missing values in each column.For categorical columns, useful inspection tools are unique() and value_counts():
print(df["City"].unique())
print(df["City"].value_counts())
unique() lists the distinct values, and value_counts() counts how often each distinct value occurs.
New columns are created from arithmetic on existing ones, and the operations are applied to every row automatically:
import pandas as pd
df = pd.DataFrame({"Maths": [90, 85, 78], "Science": [88, 92, 80]})
df["Total"] = df["Maths"] + df["Science"]
df["Average"] = df["Total"] / 2
print(df)
The result adds a Total column holding the row-wise sums and an Average column holding the row-wise means. Conditional columns can also be created:
df["Result"] = ["Pass" if m >= 40 else "Fail" for m in df["Average"]]
The apply() method runs a function across each column (axis=0) or each row (axis=1) of a DataFrame:
import pandas as pd
df = pd.DataFrame({"Maths": [90, 85, 78], "Science": [88, 92, 80]})
print(df.apply(sum))
print(df.apply(lambda r: r["Maths"] + r["Science"], axis=1))
df.apply(sum) sums each column.df.apply(func, axis=1) applies func to every row, where the function receives the row as a Series.Series.apply(func) applies a function to each element of a Series.A user-defined function can be defined first and then passed to apply:
def grade(m):
if m >= 90:
return "A"
elif m >= 75:
return "B"
else:
return "C"
df["Grade"] = df["Maths"].apply(grade)
Real data frequently contains duplicate rows. The duplicated() method flags duplicates and drop_duplicates() removes them:
import pandas as pd
df = pd.DataFrame({"Roll": [1, 2, 2, 3], "Name": ["A", "B", "B", "C"]})
print(df.duplicated())
print(df.drop_duplicates())
df.duplicated() returns a boolean Series marking each duplicated row after the first.df.drop_duplicates() removes the duplicate rows, keeping the first occurrence.subset restricts duplicate checking to chosen columns: df.drop_duplicates(subset=["Name"]).Precise selection uses loc for labels and iloc for positions, and both support conditional filtering:
print(df.loc[df["Marks"] > 80])
print(df.loc[df["City"] == "Delhi", ["Name", "Marks"]])
print(df.iloc[1:4, 0:2])
df.loc[condition] returns all rows satisfying the condition.df.loc[rows, columns] selects rows and columns by label in one step.df.iloc[r1:r2, c1:c2] selects a block by integer positions, with the end excluded.Logical combinations with & (AND), | (OR), and ~ (NOT) build complex filters:
print(df.loc[(df["Marks"] > 70) & (df["City"] == "Delhi")])
Parentheses around each condition are mandatory when combining filters.
pivot_table() summarises data by crossing two categorical columns and aggregating a value column:
import pandas as pd
df = pd.DataFrame({
"City": ["Delhi", "Delhi", "Mumbai", "Mumbai"],
"Year": [2023, 2024, 2023, 2024],
"Sales": [100, 120, 150, 170]
})
print(df.pivot_table(values="Sales", index="City", columns="Year", aggfunc="sum"))
The result is a small table with one row per city and one column per year, each cell holding the summed sales. The default aggregation is the mean, and aggfunc can be changed to sum, count, max, min, or a list of functions.
stack() converts a DataFrame into a Series with a multi-level index, and unstack() reverses it:
s = df.groupby(["City", "Year"])["Sales"].sum()
print(s)
print(s.unstack())
stack and unstack are used to move between the long and wide forms of data, which is important when preparing data for charts or reports.
import pandas as pd
df1 = pd.DataFrame({"Roll": [1, 2], "Name": ["A", "B"]})
df2 = pd.DataFrame({"Roll": [3, 4], "Name": ["C", "D"]})
print(pd.concat([df1, df2], ignore_index=True))
Vertical concatenation appends rows; axis=1 appends columns instead.
marks = pd.DataFrame({"Roll": [1, 2, 3], "Marks": [88, 92, 78]})
city = pd.DataFrame({"Roll": [1, 2, 3], "City": ["Delhi", "Mumbai", "Pune"]})
merged = pd.merge(marks, city, on="Roll")
print(merged)
The how parameter controls whether the join is inner, left, right, or outer, exactly as in SQL.
A typical program combines all the techniques of this chapter:
import pandas as pd
df = pd.read_csv("students.csv")
df = df.dropna()
df["Total"] = df["Maths"] + df["Science"] + df["English"]
df = df.drop_duplicates(subset=["Roll"])
summary = df.groupby("City")["Total"].agg(["count", "mean"])
print(summary)
print(df.loc[df["Total"] > 200, ["Name", "Total"]])
df.to_csv("report.csv", index=False)
The program reads the data, removes missing rows, computes a new column, drops duplicates, groups and aggregates the results, filters the top students, and exports a clean report file.
| Method | Purpose |
|---|---|
df.info() |
Rows, columns, dtypes, non-null counts |
df.describe() |
Statistical summary |
df.shape |
Number of rows and columns |
df.isnull().sum() |
Missing values per column |
df["col"].unique() |
Distinct values of a column |
df["col"].value_counts() |
Frequency of each value |
| Function | Action |
|---|---|
df.apply(func, axis=1) |
Apply function to each row |
df.duplicated() |
Flag duplicate rows |
df.drop_duplicates() |
Remove duplicate rows |
df.pivot_table(...) |
Summarise by rows and columns |
s.stack() / s.unstack() |
Change between long and wide form |
pd.concat([d1, d2]) |
Append rows or columns |
pd.merge(d1, d2, on="key") |
Join on a common column |
dropna() on a dataset where the empty cells are meaningful, thereby losing useful rows.df["Total"] = df["Maths"] + df["Science"] + df["English"] when one subject column contains NaN, because the whole row becomes NaN.loc, producing a confusing "truth value is ambiguous" error.df.apply(func) without axis=1 and expecting row-wise results; the default is column-wise.pivot_table averages by default; the default is the mean, but it is easy to forget to set aggfunc explicitly.stack with unstack: stack moves columns into the index, while unstack does the reverse.pd.concat without ignore_index=True and getting repeated index labels.apply defaults to columns (axis=0), and dropna defaults to rows.value_counts() is the fastest way to answer "how many times does each value occur" questions.& or | with parentheses around every condition.stack/unstack as the tools for converting between long and wide formats.print(df.head()) so the examiner can verify the step-by-step logic.Data Handling using Pandas brings together everything needed to work with realistic datasets. Inspection methods such as info(), describe(), unique(), and value_counts() reveal what the data contains; arithmetic between columns and the apply() method create derived values; duplicated() and drop_duplicates() remove redundant rows; pivot_table(), stack(), and unstack() reshape tables; and concat() and merge() combine sources. Combined into the standard pipeline of read, clean, compute, analyse, present, and export, these operations turn raw files into meaningful reports. This toolkit directly supports the practical file work that follows, where complete programs of exactly this kind are written, executed, and documented.