Section 5 · Answering Real Questions
Reproducible Analysis
18 min3 min readPython exercise
Lesson at a glance
Turn a one-off analysis into a reproducible one with parameters, functions, assertions, saved outputs and a clean top-to-bottom notebook, and see where to go after this course.
No video here — just the real thing: a written lesson, runnable examples, a quiz and practice.
The Q4 answer is written. In three months the head of growth will ask the same question about Q1, and the person answering might be you, a colleague, or you having forgotten every detail. An analysis that only works in the notebook where it was born is a one-off. One that anyone can rerun from the raw files and get the same numbers is an asset. The difference is a handful of habits.
The shape of a rerunnable analysis
import pandas as pd
# Parameters: everything that changes between runs lives here.
ORDERS_FILE = "orders.csv"
ITEMS_FILE = "order_items.csv"
QUARTER = "2025Q4"
EXCLUDE_STATUSES = ["cancelled"]
def load_orders(orders_file, items_file):
"""One row per order with revenue (after discounts, no shipping)."""
items = pd.read_csv(items_file)
orders = pd.read_csv(orders_file, parse_dates=["order_date"])
items["revenue"] = items["quantity"] * items["unit_price"] * (1 - items["discount"])
revenue = items.groupby("order_id", as_index=False)["revenue"].sum()
df = orders.merge(revenue, on="order_id", how="left", validate="one_to_one")
assert df["order_id"].is_unique, "duplicate orders"
assert df["revenue"].notna().all(), "orders without items"
return df
def quarter_summary(df, quarter, exclude):
kept = df[~df["status"].isin(exclude)]
in_q = kept[kept["order_date"].dt.to_period("Q") == quarter]
assert len(in_q) > 0, f"no orders in {quarter}"
return {
"quarter": quarter,
"revenue": round(in_q["revenue"].sum(), 2),
"orders": len(in_q),
"customers": in_q["customer_id"].nunique(),
"aov": round(in_q["revenue"].mean(), 2),
}
df = load_orders(ORDERS_FILE, ITEMS_FILE)
summary = pd.DataFrame([quarter_summary(df, q, EXCLUDE_STATUSES) for q in ["2025Q3", QUARTER]])
print(summary)
print(f"pandas {pd.__version__}")Four ideas carry it. Parameters at the top name every input and every decision, including the revenue definition, so next quarter’s run changes one line. Functions hold the steps, take their inputs as arguments and return results, so they never depend on a variable left over from somewhere else. Assertions state what must be true of the data before anything is computed from it, as you did in Lesson 3.5. And the version print records which pandas produced the numbers, because defaults do change between major versions.
Notebook hygiene
Notebooks are excellent for exploring and dangerous for reporting, because cells can run in any order and variables outlive the cells that made them. Before you share one:
- Restart and Run All. If it fails or the numbers change, the notebook depended on hidden state.
- Read files, never edit them. Keep raw exports untouched in a
data/rawfolder; cleaning happens in code, so it can be repeated. - Move reusable code out. Once two notebooks need
clean_orders, it belongs in a.pyfile you import. - Write outputs to files.
summary.to_csv("q4_summary.csv", index=False)produces the numbers the slide uses; copying from the screen invites typos. - Write the definition next to the number. A short Markdown cell saying what “revenue” includes saves an argument later.
What you can do now
You started this course unable to write a line of Python. You can now load and inspect any CSV, clean real-world mess (blanks, typos, money as text, ambiguous dates, duplicates), join and reshape tables, summarise them by group and over time, describe distributions honestly, and turn all of it into an answer with evidence and caveats. That is the daily work of a data analyst.
Where to go next depends on the questions you want to answer. SQL for Analysts uses the same Cartwheel data in a database, which is where most company data actually lives. The Machine Learning Crash Course picks up churn.csv and asks the next question: which customers are about to leave? Whichever you choose, keep the habits from this course: check before you trust, write the definition down, and make it rerunnable.
Key takeaways
- A reproducible analysis gives the same result when someone else runs it from the raw files, top to bottom, with no manual steps.
- Put inputs and choices in named parameters at the top (file paths, the quarter, the revenue definition), so rerunning for a new period means changing one line.
- Functions hold the steps you repeat; assertions state what the data must look like before results are trusted.
- Use Restart and Run All before sharing a notebook, and save results with
to_csv(..., index=False)instead of copying numbers by hand.