Beginner: data foundations · Cleaning, exploring and visualising data · topic 18 of 62 · 35 min
Cleaning messy data
Explanation
Why cleaning comes first
If "Bengaluru", "Bangalore" and " bengaluru " are three different cities in your data, your sales-by-city chart is wrong. If a price column is text, you cannot add it up. A model trained on dirty data learns the dirt. People often say "garbage in, garbage out", and they are right.
The common problems and their fixes
| Problem | How it looks | pandas fix |
|---|---|---|
| Missing values | Blank cells, NaN, None | df.isna().sum(), dropna(), fillna(...) |
| Duplicates | The same order twice | df.duplicated().sum(), drop_duplicates() |
| Wrong types | Price as "1,200" (text) | str.replace(",", ""), pd.to_numeric(..., errors="coerce") |
| Extra spaces and case | " pune", "PUNE" | str.strip().str.title() |
| Inconsistent categories | Bangalore vs Bengaluru | replace({"Bangalore": "Bengaluru"}) |
| Dates as text | "05/01/2025" | pd.to_datetime(..., format="%d/%m/%Y") |
| Impossible values | Age 250, negative quantity | Filter or set to missing after checking |
Missing values: drop or fill?
NaN ("not a number") is how pandas marks a missing value. You can drop rows with missing values, but if many rows have gaps you lose a lot of data. You can fill (impute) them, for example with the median of the column. The median is often safer than the mean because a few extreme values do not move it. Whatever you do, write it down, and consider adding a column that says the value was filled.
df["salary"].isna().sum() # how many are missing
df["salary"] = df["salary"].fillna(df["salary"].median())
df = df.dropna(subset=["customer_id"]) # rows without an id are uselessTurning text into numbers safely
df["price"] = pd.to_numeric(
df["price"].str.replace(",", "").str.replace("₹", ""),
errors="coerce",
)Dates
Indian data often writes dates as day/month/year, while some tools assume month/day/year. "05/01/2025" is 5 January in India but May 1 in the US. Always pass the format explicitly, for example format="%d/%m/%Y", and check a few rows afterwards.
A safe cleaning routine
- Keep the raw file unchanged. Clean a copy in code.
- Look first: info(), isna().sum(), value_counts() on text columns, describe() on numbers.
- Fix one problem at a time and re-check the counts after each step.
- Record every decision (why you dropped or filled) in comments or a notes cell.
- Put the steps in a function so next month's file gets exactly the same treatment.
Common mistakes
- Filling missing values with 0 when 0 is a real value (a salary of 0 is not "unknown"). Fix: use the median, a flag, or leave it missing.
- Dropping all rows with any missing value and losing half the data. Fix: drop only on the columns that truly matter.
- Removing "outliers" that are real (a genuine ₹5 lakh order). Fix: investigate before deleting.
- Cleaning by hand in Excel, so nobody can repeat it. Fix: clean in code.
Need help?
Stuck on a word or an idea? Search this course, or every course, and jump straight to the explanation or a worked question.
Try:
Watch the lesson
Cleaning messy data · 1/6
Real data is messy. In this lesson you will learn to clean it carefully.
Prefer a video by a teacher? Find free videos on “data cleaning pandas missing values duplicates tutorial” on YouTube ↗
In real life: Cleaning a survey from a Google Form
An NGO collects household data from field workers through an online form. City names arrive as "bangalore", "Bengaluru " and "BLR"; incomes arrive as "12,000" or "12k"; some phone numbers are blank. Before any report, an analyst runs a cleaning script: trims spaces, maps city aliases to one name, converts incomes to numbers (flagging the ones it cannot read) and removes exact duplicate submissions. Only then are the district-wise averages trusted.
Practice (0/3 done)
Write clean_city(name) that returns a tidy city name: strip spaces, then title-case it ("pune" → "Pune"), then map the aliases "Bangalore" and "Blr" to "Bengaluru", and "Bombay" to "Mumbai". An empty or all-space name returns None.
Write to_number(text) that converts money text to a float: remove "₹", commas and spaces, then convert. If it still cannot be converted (or is empty), return None, like errors="coerce". Examples: "₹1,200" → 1200.0, " 450.50 " → 450.5, "twelve" → None.
Write fill_with_median(values) where missing values are None. Return a new list where each None is replaced by the median of the values that are present (use statistics.median). If every value is missing, return the list unchanged.
Quick quiz
Read more (free)
Related help
Before this, learn
This topic builds on these. If something here feels new, open them first.
Related topics
- Grouping, joining and reshapingCleaning, exploring and visualising data · same module
- NumPy: fast arrays of numbersCleaning, exploring and visualising data · same module
- Text functionsSQL and Databases · Functions, CASE and NULL
- String processingPython Programming · Working with data
- SELECT and WHERE: finding rowsBackend Development · Databases and SQL basics
- UPDATE and DELETE safelySQL and Databases · Changing data, transactions and ACID
Questions people ask about this
Open a question to see the answer and why. The first ones are this topic's own quiz, so try the quiz above before you peek.
Why is the median often a better fill value than the mean for incomes?
Answer: A few very large incomes pull the mean up but barely move the median
The median resists outliers, so it is a more typical value for skewed data.
What does pd.to_numeric(col, errors="coerce") do with "abc"?
Answer: Turns it into NaN
coerce converts what it can and marks the rest as missing.
A date column has "05/01/2025" in Indian style. What should you do?
Answer: Pass format="%d/%m/%Y" explicitly
Guessing may read it as May 1. An explicit format avoids the mix-up.
Which is the safest habit?
Answer: Keep the raw file unchanged and clean a copy in code
Raw data stays as evidence; code makes the cleaning repeatable.
An order of ₹4,50,000 appears in a store where most orders are under ₹5,000. What should you do?
Answer: Investigate: it may be a real bulk order or a typing error
Extreme values can be real. Check before removing them.
Why might WHERE city = 'Pune' miss a row whose city looks like Pune on screen?Related
Answer: Because the stored value may have a hidden space or different case, such as ' Pune' or 'PUNE'
Clean both sides with TRIM and LOWER, or clean the data when it is saved.
From Text functions
A salary cell is blank. Which choice is usually most honest when you store it?Related
Answer: None, meaning missing
0 is a real salary and would drag the average down. None marks the value as missing so you can decide later, openly, how to handle it.
How do you find rows where email is missing?Related
Answer: WHERE email IS NULL
NULL is not equal to anything, so = NULL never matches. Use IS NULL.
What is the safest way to run a DELETE on a live table?Related
Answer: Preview the same WHERE with a SELECT, then run the DELETE, ideally inside a transaction
Check the rows and the count first, and keep a way back.
Pass the quiz (60% or more) or mark this topic as done when you are ready.
Your progress is saved on this device only.
Next steps
- 3 more topics in “Cleaning, exploring and visualising data” before its exam: Grouping, joining and reshaping, Exploratory data analysis (EDA), Visualising data honestly.
- Module 4 exam: Cleaning, exploring and visualising data · 12 questions · 25 min, without help. 6 topics of this module still to finish first.
- Then the next module, The ML workflow, regression and classification. 62 topics left in the course before the final exam.