Each run starts with fresh data. Download any exported files before another run. Your written answers and code drafts are saved on this device; export your work to keep a backup.
M11C01 · Explore · predict · practice
Find an exact repeated record
duplicated() marks repeated rows. By default, the first occurrence is kept unmarked and later copies are marked True. With keep=False, every member of a repeated set is marked.
Twelve rows remain. Other data-quality problems are still present and need separate treatment.
Compare your explanations
Read. It shows both the original row and its duplicate so we can compare them.
Predict. Two displayed rows for S003, but only one extra copy.
Explain. No. Different people can share a name; use the intended record key and relevant fields.
One quick check
What does duplicated() count by default here?
What you should be able to explain. Inspect repeated records before removing them.
M11C02 · Explore · predict · practice
A repeated ID is not always an exact duplicate
subset lets you check only the columns that define a record key. Two rows can share an ID but disagree on a score. Keeping the last one is defensible only when a documented order says it is the latest record.
Watch for this. In a transaction table, repeated student IDs may be expected; define what one row represents.
Your turn
Assume the later Updated date is the authoritative revision. Parse Updated, sort chronologically, and keep the latest row per Student_ID. Store the retained rows in result, sorted by Student_ID in ascending order.
For the code check, keep these result variable names: result. Different valid approaches are welcome.
Show a hint
Date parsing is introduced in Module 13: use pd.to_datetime with format="%Y-%m-%d". Sort by Updated before drop_duplicates(subset="Student_ID", keep="last"), then sort the retained rows by Student_ID.
S001 keeps score 88 from October 3; S002 keeps 72. The decision follows the stated update policy.
Compare your explanations
Read. Student_ID.
Predict. No. Their dates and scores differ.
Explain. We could discard the correct observation; the meaning of the records and update order matters.
One quick check
Does keep="last" automatically know the newest date?
What you should be able to explain. Choose a key and a documented conflict rule.
M11C03 · Explore · predict · practice
Flag impossible values instead of hiding them
Data can have the right type and still be invalid. If Attendance is a percentage, its allowed range is 0 through 100. A Boolean mask can create a review table before you decide how to repair the source.
Watch for this. The allowed range comes from the meaning of the variable, not from pandas.
Your turn
Preserve the source Attendance values in Attendance_raw. Convert Attendance to a nullable numeric column and set its out-of-range values to missing. Store the affected rows in result with columns Student_ID, Attendance_raw, and Attendance.
For the code check, keep these result variable names: result. Different valid approaches are welcome.
Show a hint
Use a copy, astype("Float64"), and one .loc[mask, column] assignment.
The original 105 is retained for follow-up. The cleaned measurement is marked unknown, not changed to a guessed value.
Compare your explanations
Read. It reverses True and False, so rows outside the range are selected.
Predict. S011, whose Attendance value is 105.
Explain. We do not know the correct value. Clipping can hide a recording error and overstate attendance.
One quick check
Is a numeric value always a valid measurement?
What you should be able to explain. Validate values against explicit domain rules.
M11C04 · Explore · predict · practice
Turn expectations into assertions
An assertion stops execution if an expectation is false. It is useful for classroom checks and analysis pipelines. Validate identity, required values, and ranges separately so a failure has a clear meaning.
Read the example
df = students()
assert df["Student_ID"].notna().all(), "A student ID is missing"
assert df["Student_ID"].is_unique, "Student IDs must be unique here"
assert df["Score"].between(0, 100).all(), "Score outside 0-100"
result = {"rows": len(df), "valid_ids": True, "valid_scores": True}
print(result)
Watch for this. Python can disable assert statements in optimized runs; formal applications may need explicit validation errors.
Your turn
Add checks requiring Campus to be RAK or Dubai and Attendance to be 0-100. Store the two Boolean results in a dictionary named result with keys campus_ok and attendance_ok.
For the code check, keep these result variable names: result. Different valid approaches are welcome.
Show a hint
Use .isin([...]).all() for an allowed-label check.