Skip to content
Aabha AI Academy
Skip to reading

Python · Module 8

Answers and explanations · pandas tables

Compare these references after your own attempt. You can read them at any time; they do not record a live model or vendor run.

Module 8

Three valid rows remain: data/30 and two python rows totaling 45. The unknown, blank-topic, negative and fractional-minute rows are rejected. No unknown value is invented.

Download the complete answer

# Reference answer. Attempt the exercise first.
from io import StringIO
import pandas as pd

def clean_session_table(csv_text):
    raw = pd.read_csv(StringIO(csv_text), dtype="string", keep_default_na=False)
    clean = raw.copy()
    clean["topic"] = clean["topic"].str.strip().str.lower()
    clean["minutes"] = pd.to_numeric(clean["minutes"], errors="coerce")
    valid = (clean["topic"].ne("") & clean["minutes"].notna()
             & clean["minutes"].ge(0) & clean["minutes"].mod(1).eq(0))
    return clean.loc[valid].copy(), raw.loc[~valid].copy()

def topic_totals(accepted):
    return accepted.groupby("topic", as_index=False)["minutes"].sum().sort_values("topic")

text = "topic,minutes\n Python ,20\ndata,30\npython,25\ncharts,unknown\n,10\ndata,-3\ncharts,1.5\n"
accepted, rejected = clean_session_table(text)
summary = topic_totals(accepted)
assert len(accepted) == 3 and len(rejected) == 4
assert summary["topic"].tolist() == ["data", "python"]
assert summary["minutes"].tolist() == [30, 45]
print(summary.to_string(index=False))
# Limitation: rejected durations prevent a complete practice-time total.
# Question: can the source owner recover missing or invalid duration values?
# The separate inspection fixture: record observations before cleaning it.
inspection_text = "topic,minutes\n arrays ,15\ntables,not yet\ntables,0\n charts ,-4\n,20\n"
inspection_raw = pd.read_csv(StringIO(inspection_text), dtype="string", keep_default_na=False)
print("Inspection shape:", inspection_raw.shape)
print(inspection_raw.head().to_string())
print("Source missing markers:", inspection_raw.isna().sum().to_dict())
# Observations: topic spacing needs normalization; 'not yet' needs review;
# one empty topic is not a category, and -4 violates the duration rule.
inspection_accepted, inspection_rejected = clean_session_table(inspection_text)
assert inspection_accepted.index.tolist() == [0, 2]
assert inspection_accepted["minutes"].tolist() == [15, 0]
print("Inspection transfer checks passed")

Exit-check guide: Parsing creates structured fields; validation applies the task contract. Grouping changes one row per session to one row per topic. count can exclude missing values, while row count counts rows. Preserve rejects so another person can review each decision.

Return to this module