All explanations, questions, and verified outputs can be read here. Enable JavaScript for search, saved answers, and browser Python, or use the downloadable notebooks.
Keep this page nearby
Pandas quick reference Start with the problem you want to solve. Each recipe uses a tested course example and links to its full explanation.
Use the sidebar search for ordinary language or a method name. Open the glossary for unfamiliar terms.
Build a table from a dictionary I can turn a dictionary of lists into a DataFrame.
Show the tested example data = {"Name": ["Amira", "Bilal", "Chloe"], "Age": [20, 21, 19]}
df = pd.DataFrame(data)
print(df)
print(type(df).__name__)
print("Rows and columns:", df.shape)Watch for this: Call pd.DataFrame(...) with a capital D and F; Python names are case-sensitive.
Open the explanation and practice Select columns and keep a table I can predict whether a column selection returns a Series or a DataFrame.
Show the tested example df = students()
column = df["Score"]
table = df[["Score"]]
result = df[["Name", "Score"]]
print(type(column).__name__, column.shape)
print(type(table).__name__, table.shape)
print(result.head(3))Watch for this: df["Name", "Score"] is not the same as df[["Name", "Score"]] for these ordinary columns.
Open the explanation and practice Select rows by label or position I can read selected records and one value using meaningful labels.
Show the tested example df = students().set_index("Student_ID")
result = df.loc[["S001", "S003"], ["Name", "Score"]]
one_score = df.at["S003", "Score"]
print(result)
print("One score:", one_score)Watch for this: set_index does not automatically check that IDs are unique; uniqueness needs its own check.
Open the explanation and practice Filter with two conditions I can translate both, either, and at least into correct filter logic.
Show the tested example df = students()
mask = (df["Campus"] == "RAK") & (df["Score"] >= 80)
result = df.loc[mask, ["Student_ID", "Name", "Campus", "Score"]]
print(result)Watch for this: Do not omit the parentheses around comparisons; operator precedence can change the expression.
Open the explanation and practice Check membership or a range I can express allowed categories, numerical ranges, and excluded categories.
Show the tested example df = students()
in_program = df["Program"].isin(["AI"])
in_range = df["Score"].between(70, 90, inclusive="both")
result = df.loc[in_program & in_range, ["Name", "Program", "Score"]]
print(result)Watch for this: Do not use Program == ["AI", "IT"] to test membership; use .isin(["AI", "IT"]).
Open the explanation and practice Sort and choose a tie rule I can make the order of tied records explicit.
Show the tested example df = pd.DataFrame({
"Name": ["Chloe", "Amira", "Bilal", "Dana"],
"Score": [80, 80, 95, 80]
})
result = df.sort_values("Score", ascending=False, kind="stable")
print(result)Watch for this: Alphabetical tie order must be requested explicitly; a stable sort preserves source order instead.
Open the explanation and practice Update matching rows safely I can modify selected values using one explicit loc assignment.
Show the tested example df = students()
mask = df["Student_ID"] == "S004"
df.loc[mask, "Score"] = 67
result = df.loc[mask, ["Student_ID", "Name", "Score"]]
print(result)Watch for this: Repeatedly running an incremental update on the same table would repeat the bonus; this cell starts with a fresh table each time.
Open the explanation and practice Convert messy numbers Audit conversion failures before deciding how to handle them.
Show the tested example source = pd.Series(["88", "absent", None, "72"], dtype="string")
numbers = pd.to_numeric(source, errors="coerce")
invalid = source.notna() & numbers.isna()
result = pd.DataFrame({"Original": source, "Number": numbers, "Invalid_text": invalid})
print(result)Watch for this: Do not silently turn every conversion failure into zero.
Open the explanation and practice Understand missing, empty, and zero Define what missing means in your dataset.
Show the tested example values = pd.Series([0, None, "", pd.NA, np.nan], dtype="object")
result = values.isna()
print(result.tolist())
print("Missing count:", result.sum())Watch for this: Use .isna(), not == np.nan, to detect missing values.
Open the explanation and practice Find repeated IDs Choose a key and a documented conflict rule.
Show the tested example df = pd.DataFrame({"Student_ID": ["S001", "S001", "S002"], "Updated": ["2026-10-01", "2026-10-03", "2026-10-02"], "Score": [80, 88, 72]})
result = df.loc[df.duplicated(subset=["Student_ID"], keep=False)]
print(result)
print("Exact duplicates:", df.duplicated().sum())Watch for this: In a transaction table, repeated student IDs may be expected; define what one row represents.
Open the explanation and practice Clean whitespace and text Standardize categories without destroying their meaning.
Show the tested example df = raw_students()
df["Name"] = df["Name"].astype("string").str.strip()
result = df.loc[df["Student_ID"] == "S001", ["Student_ID", "Name"]]
print(result)Watch for this: An unrecognized value passed through a dictionary map becomes missing; inspect unmatched labels.
Open the explanation and practice Parse dates deliberately Parse known date formats explicitly.
Show the tested example source = pd.Series(["2026-09-01", "2026-09-03", "2026-02-30"], dtype="string")
result = pd.to_datetime(source, format="%Y-%m-%d", errors="coerce")
print(result)
print("Unparsed dates:", result.isna().sum())Watch for this: Inspect parsing failures; errors="coerce" does not repair the source date.
Open the explanation and practice Map labels from a dictionary Check what a lookup leaves unmatched.
Show the tested example codes = pd.Series(["AI", "IT", "CS", None], dtype="string")
labels = {"AI": "Artificial Intelligence", "IT": "Information Technology"}
result = pd.DataFrame({"Code": codes, "Label": codes.map(labels)})
print(result)Watch for this: The meaning of a code must come from a stated codebook, not a guess.
Open the explanation and practice Summarize each group Summarize each group with readable labels and counts.
Show the tested example df = students()
result = df.groupby("Campus", as_index=False).agg(Students=("Student_ID", "size"), Mean_score=("Score", "mean"))
print(result.round(2))Watch for this: A mean without its supporting count can hide a very small group.
Open the explanation and practice Return a group result to each row Use transform when the result belongs beside the original records.
Show the tested example df = students()
df["Program_mean"] = df.groupby("Program")["Score"].transform("mean")
df["Difference"] = df["Score"] - df["Program_mean"]
result = df[["Student_ID", "Program", "Score", "Program_mean", "Difference"]]
print(result.round(2))Watch for this: A group-relative label and a fixed-threshold label answer different questions.
Open the explanation and practice Audit a join Use indicator to make unmatched records visible.
Show the tested example audit = students().merge(assessment(), on="Student_ID", how="outer", indicator=True, validate="one_to_one")
result = audit.loc[audit["_merge"].ne("both"), ["Student_ID", "_merge"]]
print(result)
print("All merged rows:", len(audit))Watch for this: Pandas may match missing keys to other missing keys; audit or reject null keys before important merges.
Open the explanation and practice Prevent a join from multiplying rows Check key uniqueness before trusting merged row counts.
Show the tested example bad_lookup = pd.concat([departments(), departments().iloc[[0]]], ignore_index=True)
blocked = False
try:
students().merge(bad_lookup, on="Program", validate="many_to_one")
except pd.errors.MergeError:
blocked = True
print("Blocked: Program is not unique in the lookup.")
result = students().merge(bad_lookup, on="Program")
print("Rows without validation:", len(result))Watch for this: validate checks the relationship; it does not decide how to repair conflicting records.
Open the explanation and practice Stack batches of rows Use concat for batches with the same meaning and schema.
Show the tested example df = students()
first = df.iloc[:6]
second = df.iloc[6:]
result = pd.concat([first, second], ignore_index=True)
print(result[["Student_ID", "Name"]])Watch for this: Build a list of batches and concatenate once instead of repeatedly growing a DataFrame in a loop.
Open the explanation and practice Change wide data to long Long form keeps one measured value per row.
Show the tested example wide = students().head(3)[["Student_ID", "Score", "Attendance"]]
result = wide.melt(id_vars="Student_ID", value_vars=["Score", "Attendance"], var_name="Measure", value_name="Value")
print(result)Watch for this: A shared Value column may contain measures with different units; keep and use Measure.
Open the explanation and practice Read and export CSV Inspect imports and choose export columns deliberately.
Show the tested example df = pd.read_csv(DATA_DIR / "students.csv", dtype={"Student_ID": "string"})
result = df.loc[df["Score"].ge(85), ["Student_ID", "Name", "Score"]]
result.to_csv(OUTPUT_DIR / "high_scores.csv", index=False)
print(result)
print("Saved outputs/high_scores.csv")Watch for this: CSV does not preserve every pandas dtype. Check types and missing-value rules when reloading.
Open the explanation and practice Select an Excel sheet Excel I/O needs a workbook path and the correct worksheet.
Show the tested example df = pd.read_excel(DATA_DIR / "students.xlsx", sheet_name="Students", engine="openpyxl")
result = df.groupby("Campus", as_index=False)["Score"].mean()
result.to_excel(OUTPUT_DIR / "campus_report.xlsx", sheet_name="Summary", index=False, engine="openpyxl")
print(result.round(2))Watch for this: If openpyxl is missing, install the provided requirements before running this cell.
Open the explanation and practice Query a SQLite table Pandas can receive SQL results without loading every source row.
Show the tested example with sqlite3.connect(":memory:") as connection:
students().to_sql("students", connection, index=False, if_exists="replace")
result = pd.read_sql_query(
"SELECT Student_ID, Name, Score FROM students WHERE Score >= ? ORDER BY Score DESC",
connection, params=(85,))
print(result)Watch for this: Only use if_exists="replace" here on the temporary classroom table; on a real database it replaces the existing table.
Open the explanation and practice Expose missing calendar dates A gap in records is not automatically a zero.
Show the tested example df = attendance()
df["Date"] = pd.to_datetime(df["Date"], format="%Y-%m-%d")
result = df.set_index("Date")["Visitors"].sort_index().asfreq("D")
print(result)Watch for this: asfreq does not aggregate. Ensure the date index is unique before requesting a frequency.
Open the explanation and practice Calculate a rolling average Window size and missing-data rules both affect a moving average.
Show the tested example df = attendance()
df["Date"] = pd.to_datetime(df["Date"], format="%Y-%m-%d")
daily = df.set_index("Date")["Visitors"].sort_index().asfreq("D")
result = pd.DataFrame({"Visitors": daily, "Mean_3_Days": daily.rolling(3, min_periods=3).mean()})
print(result.round(2))Watch for this: Sort time data before rolling. Otherwise the window follows an unintended order.
Open the explanation and practice Flatten nested JSON Verify semantic equality after changing a data representation.
Show the tested example path = DATA_DIR / "public" / "penguins.nested.json"
payload = json.loads(path.read_text(encoding="utf-8"))
result = pd.json_normalize(payload, sep=".")
print(result.head(3))
print("Columns:", result.columns.tolist())
print("Known body masses:", result["measurements.body_mass_g"].count())Watch for this: The nested structure is a course-created representation, not a claim about an upstream research API.
Open the explanation and practice