Contents/ Part V Β· Putting It All Together/ Chapter 30

Case Study: Multi-File, Multi-Date EDA

Three messy exports, mismatched keys, four date formats, currency stored as text, duplicates and orphans. This is the data-cleaning work that precedes every analysis in the book, turning raw files into one table you can actually trust, and only then exploring it.

⏱️ ~22 min read
🐍 Full notebook included
πŸ“Š Chapter 30

Every earlier chapter began with a tidy dataframe. This one is about how you earn that dataframe. Real data arrives split across separate exports and riddled with the small inconsistencies that silently corrupt results: the same country spelled four ways, a date that could be March or April, a price stored as the text "$1,299.00", rows duplicated by an export bug. The work of joining and cleaning those files deserves the same rigor as any model, because a mistake here quietly poisons every number downstream.

🧹
Data wrangling is the process of turning raw, messy sources into one clean, tidy table: normalize missing values, clean the join keys, drop duplicates, parse dates and numbers, standardize categories, join, and validate before you trust a single total.
🎯
What this case study ties together

It is the exploratory-data-analysis groundwork the whole book stands on: a realistic multi-file merge, disciplined date and type parsing, duplicate and orphan detection, a validation checklist, and honest handling of the missing data that a clean join reveals.

1

The Problem, and the Three Files (Steps 1–2)

The business question is simple, how is revenue trending and who returns the most, but the data lives in three separate exports that must be joined first: an orders file, a customers file, and a returns file. Each has its own quirks, and they link on a shared customer_id and order_id that do not quite match out of the box.

πŸ“‚ Dataset Β· three raw CSV files

orders (mixed date formats, currency as text, duplicate rows, missing amounts, a few orphan customer ids), customers (id casing and whitespace, four spellings per country, duplicate rows, some missing regions), and returns (its own date format). The notebook turns all three into one clean table.

2

The Mess, One Class at a Time (Steps 3–8)

Good cleaning is methodical: fix one kind of problem at a time, in the right order. We normalize the many spellings of missing ("", N/A, null, -) into a single NaN; clean the join key on both tables (strip whitespace, uppercase) so it will match; drop duplicate rows (40 orders and 15 customers); parse each date column with its own format; turn currency text into numbers (37 orders turn out to have no amount); and standardize the categories so four spellings of one country collapse to one.

One class of mess at a time: raw text becomes clean, typed data RAW (all text) CLEAN (typed) "$1,299.00"1299.0float "03/15/2024"2024-03-15datetime "SHIPPED"shippedcategory "USA" / "U.S."United Statescategory "c0007 "C0007clean key "N/A" / ""NaNmissing
3

Join, and Validate (Steps 9–10)

Now the tables can be joined. A left join on the cleaned customer_id attaches each order's region, and indicator=True reveals 8 orphan orders whose id matches no customer, a data-quality issue to report, not hide. Cleaning the key first is what makes this work: joined on the raw keys, about a quarter of orders would have silently failed to match. A second join flags returns.

Three files join on shared keys into one analysis-ready table orders1,200 rows customers300 rows returns150 rows merge(on=key) clean table 1,200 orders × 9 cols validate: 8 orphans flagged 37 missing amounts

Then we validate before trusting anything: assert the order ids are unique, the dates fall in range, amounts are non-negative, exactly three regions remain, and surface what is still imperfect (the 37 missing amounts, the 8 orphans). Cheap assertions here catch the errors that would otherwise silently reach a dashboard.

4

The Payoff: Trustworthy EDA (Step 11)

Only now, on a table we trust, do the answers appear, and every one of them would have been wrong on the raw files: inflated by duplicates, scattered by region spellings, or crashed by text amounts. Realized revenue is about 388,000 dollars at a 13.8% return rate, with the United States the largest market (roughly 194,000 dollars, about half the total) and a steady monthly order flow.

Two clean charts: orders per month showing a steady flow, and a horizontal bar chart of realized revenue by region led by the United States at 194,000 dollars
From the notebook · Step 11
The business answers, finally trustworthy: a steady monthly order flow (left) and realized revenue by region (right), led by the United States at about 194,000 dollars, roughly half the total.
5

The Silent Date Trap, and the Memo (Step 12 & beyond)

One cleaning bug deserves special fear: the mis-parsed date. Order dates like 03/04/2024 are ambiguous, March 4th or April 3rd, and guessing wrong produces no error at all, just a wrong answer. On this data, parsing day-first instead of month-first leaves close to 300 dates silently swapped into the wrong month, quietly distorting the monthly trend even though the raw text never changed. The defense is to never let the parser guess: set the convention explicitly, coerce failures, and sanity-check the result.

Two monthly order curves from the same date column: the correct month-first parse and the wrong day-first parse diverge, showing how a silent date bug distorts the trend
From the Take It Further notebook
The same date column, two parse rules, two different histories. Nothing errors out, but close to 300 dates silently swap month and day, and the monthly curves diverge. A date bug produces no error message, only wrong answers.

Memo to the analytics team

After consolidating the three exports into one clean table (1,200 unique orders across 300 customers), realized revenue was about 388,000 dollars at a 13.8% return rate, led by the United States.

Two data-quality issues to fix at the source

37 orders exported with no amount (so revenue is a slight under-count, the plausible range is about 388,000 to 399,000 dollars), and 8 orders reference customers missing from the customer file.

The repeatable checklist

(1) normalize missing-value sentinels, (2) clean and standardize join keys on every table, (3) drop duplicate rows, (4) parse each date with its own explicit format, (5) convert currency and numeric text to numbers, (6) standardize text categories, (7) join with an indicator to catch orphans, and (8) assert structural checks before trusting any total.

🐍

Do the whole clean-up in Python

The companion notebook is the full 12-step wrangling workflow: it loads the three messy files, normalizes missing-value sentinels, cleans the join keys, drops duplicates, parses three date formats and the currency amounts, standardizes the region and status categories, joins everything with an indicator to catch orphans, runs a validation checklist, and only then explores the clean data, all library-first with pandas.

πŸ““ View Notebook (code & outputs) β–Ά Open in Colab ⬇ View / Download on GitHub

View opens the rendered notebook instantly. Open in Colab runs it live. To run locally, install numpy, pandas, matplotlib, and openpyxl.

πŸŽ“ Key Takeaways

  • βœ“Cleaning is the job: turning three messy files into one trustworthy table is where analyses are won or lost.
  • βœ“Normalize keys before joining: on the raw keys about a quarter of orders silently failed to match; cleaning cut orphans to 8.
  • βœ“Parse dates and numbers explicitly: a wrong date assumption swapped close to 300 dates with no error at all.
  • βœ“Deduplicate before you aggregate: 40 duplicate orders would have inflated every revenue total.
  • βœ“Validate, and be honest about gaps: assert your assumptions, and report the range the 37 missing amounts imply (about 388k to 399k dollars).
6

Take It Further

Five deeper cuts at data cleaning in the companion notebook:

1

The day-first date trap

Parse the dates both ways and count how many silently swap month and day.

Hint: compare dayfirst=False and dayfirst=True, always with errors='coerce'.
2

Clean the key, or lose the join

Join on the raw keys versus the cleaned keys and measure how many matches a dirty key silently drops.

Hint: count orphans from the merge indicator, before and after normalizing the id.
3

Validate the merge with a contract

Use validate="m:1" so a bad key relationship raises an error instead of a quiet bug.

Hint: it enforces that each customer id is unique in the customer table.
4

Wrap it in a reusable pipeline

Fold every step into one clean() function with assertions, a data contract for next month's export.

Hint: end the function with assert checks on ids, dates, amounts, and statuses.
5

How much do the gaps move revenue?

Bracket the headline by excluding versus imputing the missing amounts.

Hint: compare exclude, overall-mean impute, and regional-mean impute.
πŸ““

All five, worked in a companion notebook

A second notebook, Take It Further, rebuilds this chapter's clean-up and works every extension with visuals and explanations: the day-first date trap, the cost of a dirty join key, a merge validated by a data contract, a reusable asserting pipeline, and a revenue-sensitivity analysis of the missing amounts.

πŸ““ View Notebook (code & outputs) β–Ά Open in Colab ⬇ View / Download on GitHub
7

Quiz: Test Yourself

Eight questions on the wrangling workflow, from missing-value sentinels to validating a join. Answer them, hit Check Answers, and keep refining until you score 100%. Your progress is saved.

➑️
Up next

That wraps up our exploratory case studies. Next the book turns to probability, the language of uncertainty. Probability Fundamentals opens Probability with sample spaces, events, and the rules that govern chance, the foundation everything downstream is built on.